ADC/device/adc_device.h
2024-12-10 17:02:22 +03:00

198 lines
4.8 KiB
C++

#pragma once
#include <algorithm>
#include <memory>
#include <ranges>
#include <system_error>
#include <unordered_map>
#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<adc::AdcGenericDeviceErrorCode> : 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<AdcGenericDeviceErrorCode>(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<int>(ec), AdcGenericDeviceErrorCategory::get());
}
template <typename IdentT, interfaces::adc_device_attr_c AttributeT, interfaces::adc_device_cmd_c CommandT>
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<CommandT>(std::move(cmd))});
return *this;
}
template <typename... CtorArgTs>
AdcGenericDevice& addCommand(CtorArgTs&&... ctor_args)
{
return addCommand({std::forward<CtorArgTs>(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<AttributeT>(std::move(attr))});
return *this;
}
template <typename... CtorArgTs>
AdcGenericDevice& addAttribute(CtorArgTs&&... ctor_args)
{
return addAttribute(AttributeT(std::forward<CtorArgTs>(ctor_args)...));
}
AdcGenericDevice& delAttribute(const attr_ident_t& attr_ident)
{
_deviceAttributes.erase(attr_ident);
return *this;
}
template <std::ranges::output_range<cmd_ident_t> ResultT>
AdcGenericDevice& commandIdents(ResultT& idents)
{
std::ranges::copy(_deviceCommands | std::views::keys, std::back_inserter(idents));
return *this;
}
template <std::ranges::output_range<attr_ident_t> ResultT>
AdcGenericDevice& attributeIdents(ResultT& idents)
{
std::ranges::copy(_deviceAttributes | std::views::keys, std::back_inserter(idents));
return *this;
}
protected:
IdentT _ident;
// std::unordered_map<attr_ident_t, AttributeT> _deviceAttributes;
// std::unordered_map<cmd_ident_t, CommandT> _deviceCommands;
std::unordered_map<attr_ident_t, std::unique_ptr<AttributeT>> _deviceAttributes;
std::unordered_map<cmd_ident_t, std::unique_ptr<CommandT>> _deviceCommands;
};
} // namespace adc