#pragma once #include #include #include #include #include #include "adc_device_concepts.h" namespace adc { // error codes enum class AdcGenericDeviceErrorCode : int { ERROR_OK, ERROR_ATTR_IDENT, ERROR_COMMAND_IDENT, ERROR_UNKNOWN }; } // namespace adc namespace std { template <> class is_error_code_enum : public true_type { }; } // namespace std namespace adc { // error category struct AdcGenericDeviceErrorCategory : public std::error_category { AdcGenericDeviceErrorCategory() : std::error_category() {} const char* name() const noexcept { return "ADC_GENERIC_DEVICE"; } std::string message(int ec) const { AdcGenericDeviceErrorCode err = static_cast(ec); switch (err) { case AdcGenericDeviceErrorCode::ERROR_OK: return "OK"; case AdcGenericDeviceErrorCode::ERROR_ATTR_IDENT: return "invalid attribute identificator"; case AdcGenericDeviceErrorCode::ERROR_COMMAND_IDENT: return "invalid command identificator"; default: return "UNKNOWN"; } } static const AdcGenericDeviceErrorCategory& get() { static const AdcGenericDeviceErrorCategory constInst; return constInst; } }; inline std::error_code make_error_code(AdcGenericDeviceErrorCode ec) { return std::error_code(static_cast(ec), AdcGenericDeviceErrorCategory::get()); } template class AdcGenericDevice { public: typedef IdentT ident_t; typedef AttributeT attribute_t; typedef CommandT command_t; using attr_ident_t = typename AttributeT::ident_t; using cmd_ident_t = typename CommandT::ident_t; /* CONSTRUCTORS AND DESTRUCTOR */ AdcGenericDevice(const IdentT& ident) : _ident(ident) {} virtual ~AdcGenericDevice() = default; /* PUBLIC METHODS */ IdentT ident() const { return _ident; } AdcGenericDevice& operator()(const cmd_ident_t& cmd_ident) { auto it = _deviceCommands.find(cmd_ident); if (it != _deviceCommands.end()) { // it->second(); it->second->operator()(); } else { throw std::system_error(AdcGenericDeviceErrorCode::ERROR_COMMAND_IDENT); } return *this; } AttributeT& operator[](const attr_ident_t& attr_ident) { auto it = _deviceAttributes.find(attr_ident); if (it != _deviceAttributes.end()) { // return it->second; return *(it->second); } throw std::system_error(AdcGenericDeviceErrorCode::ERROR_ATTR_IDENT); } AdcGenericDevice& addCommand(CommandT&& cmd) { // _deviceCommands.insert({cmd.ident(), std::move(cmd)}); _deviceCommands.insert({cmd.ident(), std::make_unique(std::move(cmd))}); return *this; } template AdcGenericDevice& addCommand(CtorArgTs&&... ctor_args) { return addCommand({std::forward(ctor_args)...}); } AdcGenericDevice& delCommand(const cmd_ident_t& cmd_ident) { _deviceCommands.erase(cmd_ident); return *this; } AdcGenericDevice& addAttribute(AttributeT&& attr) { // _deviceAttributes.insert({attr.ident(), std::move(attr)}); _deviceAttributes.insert({attr.ident(), std::make_unique(std::move(attr))}); return *this; } template AdcGenericDevice& addAttribute(CtorArgTs&&... ctor_args) { return addAttribute(AttributeT(std::forward(ctor_args)...)); } AdcGenericDevice& delAttribute(const attr_ident_t& attr_ident) { _deviceAttributes.erase(attr_ident); return *this; } template ResultT> AdcGenericDevice& commandIdents(ResultT& idents) { std::ranges::copy(_deviceCommands | std::views::keys, std::back_inserter(idents)); return *this; } template ResultT> AdcGenericDevice& attributeIdents(ResultT& idents) { std::ranges::copy(_deviceAttributes | std::views::keys, std::back_inserter(idents)); return *this; } protected: IdentT _ident; // std::unordered_map _deviceAttributes; // std::unordered_map _deviceCommands; std::unordered_map> _deviceAttributes; std::unordered_map> _deviceCommands; }; } // namespace adc