Untitled

 avatar
unknown
plain_text
9 months ago
3.9 kB
17
Indexable
#include <array>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <optional>
#include <span>
#include <string>
#include <variant>
#include <vector>
#include <type_traits>

#if __cplusplus >= 202002L
template <typename T>
using TypeTag = std::type_identity<T>;
#else
template <typename T>
struct TypeTag
{
    using type = T;
};
#endif


namespace mock {

namespace constants {
enum class FirmwareCommand {
    IDENTITY = 0,
    STATE_PUSH = 1,
    COMMAND_COUNT 	//Please ensure this definition is always at the end.
};
} // namespace constants

namespace types {
struct IdentityInfo
{
    std::string name;
    int version;
};

struct Telemetry
{
    float temperature;
    float voltage;
};
} // namespace types

using data_t = std::span<const std::byte>;

namespace helper {
template<typename T>
std::optional<T> deserialize_payload(data_t data);

template<>
std::optional<types::IdentityInfo> deserialize_payload<types::IdentityInfo>(data_t)
{
    return types::IdentityInfo{"DeviceZ", 16};
}

template<>
std::optional<types::Telemetry> deserialize_payload<types::Telemetry>(data_t)
{
    return types::Telemetry{36.5f, 3.3f};
}
} // namespace helper

class EventBus {
  public:
    void publish(const types::IdentityInfo& info) const
    {
        std::cout << "[EventBus] Published IdentityInfo: name = " << info.name << ", version = " << info.version
                  << "\n";
    }

    void publish(const types::Telemetry& telemetry) const
    {
        std::cout << "[EventBus] Published Telemetry: temperature = " << telemetry.temperature
                  << ", voltage = " << telemetry.voltage << "\n";
    }
};

class Processor {
  public:
    void process_payload(constants::FirmwareCommand cmd_id, data_t payload) const
    {
        using payload_variant_t =
            std::variant<TypeTag<types::IdentityInfo>, TypeTag<types::Telemetry>>;

        static constexpr std::array<
            payload_variant_t, 
            static_cast<std::size_t>(constants::FirmwareCommand::COMMAND_COUNT)> 
            payload_struct_array{{
            	TypeTag<types::IdentityInfo>{}, 
            	TypeTag<types::Telemetry>{} 
            	// another commands and payload types
        }};

       const size_t index = static_cast<std::size_t>(cmd_id);

        if (index >= payload_struct_array.size())
        {
            std::cout << "[Processor] Unknown command.\n";
            
            return;
        }

        const auto& tag{payload_struct_array[index]}; 
        
        std::visit(
            [&bus = m_eventbus, payload]<typename T>(T) {
                using tag_type_t = typename T::type;

                const auto res{helper::deserialize_payload<tag_type_t>(payload)};

                if (!res.has_value()) [[unlikely]]
                {
                    std::cout << "deserialize error\n";
                    return;
                }
                
                // if u need check special type
                /*
                if constexpr (std::is_same_v<types::IdentityInfo, tag_type_t>)
                {
                    // bla bla bla
                }
                */
                bus.publish(res.value());
            },
            tag);
    }

  private:
    EventBus m_eventbus;
};
} // namespace mock

int main()
{
    using namespace mock;

    Processor processor{};

    std::vector<std::byte> fake_payload{std::byte{0x01}, std::byte{0x02}, std::byte{0x03}};

    std::cout << ">>> Processing IDENTITY...\n";
    processor.process_payload(constants::FirmwareCommand::IDENTITY, fake_payload);

    std::cout << "\n>>> Processing STATE_PUSH...\n";
    processor.process_payload(constants::FirmwareCommand::STATE_PUSH, fake_payload);

    std::cout << "\n>>> Processing UNKNOWN COMMAND...\n";
    processor.process_payload(static_cast<constants::FirmwareCommand>(999), fake_payload);

    return EXIT_SUCCESS;
}
Editor is loading...
Leave a Comment