This commit is contained in:
Timur A. Fatkhullin
2026-06-21 11:55:52 +03:00
parent 6ebea9e29d
commit a395c8006b
3 changed files with 53 additions and 14 deletions

View File

@@ -35,6 +35,8 @@ target_include_directories(
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>" "$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
) )
target_link_libraries(${PROJECT_NAME} INTERFACE snipplib)
if(BUILD_EXAM) if(BUILD_EXAM)
add_executable(device_exam examples/device_exam.cpp) add_executable(device_exam examples/device_exam.cpp)
target_link_libraries(device_exam PRIVATE ${PROJECT_NAME}) target_link_libraries(device_exam PRIVATE ${PROJECT_NAME})

View File

@@ -13,15 +13,30 @@ int main()
AdcGenericDevice<> dev; AdcGenericDevice<> dev;
dev.addAttr( dev.addAttr(
"1", [&i]() { return adc_result_t<int>{i}; }, "1", [&i]() -> adc_result_t<int> { return i; },
[&i](int ii) -> adc_error_t { [&i](int ii) -> adc_error_t {
i = ii; i = ii;
return AdcDeviceErrorCode::ERROR_OK; return AdcDeviceErrorCode::ERROR_OK;
}); },
std::tuple<double, long>{});
adc_result_t<int> ri = dev["1"]; adc_result_t<int> ri = dev["1"];
if (ri) { if (ri) {
std::println("dev[1] = {}", ri.value()); std::println("dev[1] = {}", ri.value());
} else {
std::println("cannot get dev[1] as int: {}", ri.error().message());
}
auto err = dev["1"] = 77;
if (err) {
std::println("cannot set dev[1] as int: {}", err.message());
}
adc_result_t<double> rd = dev["1"];
if (rd) {
std::println("dev[1] = {}", rd.value());
} else {
std::println("cannot get dev[1] as double: {}", rd.error().message());
} }
return 0; return 0;

View File

@@ -5,6 +5,8 @@
****************************************************************************************/ ****************************************************************************************/
#include <concepts> #include <concepts>
#include <format>
#include <functional>
#include <string> #include <string>
#include <system_error> #include <system_error>
#include <type_traits> #include <type_traits>
@@ -69,9 +71,9 @@ struct AdcDeviceErrorCategory : std::error_category {
case AdcDeviceErrorCode::ERROR_OK: case AdcDeviceErrorCode::ERROR_OK:
return "OK"; return "OK";
case AdcDeviceErrorCode::ERROR_NO_CMD_ID: case AdcDeviceErrorCode::ERROR_NO_CMD_ID:
return "invalud command ID"; return "invalid command ID";
case AdcDeviceErrorCode::ERROR_NO_ATTR_ID: case AdcDeviceErrorCode::ERROR_NO_ATTR_ID:
return "invalud attribute ID"; return "invalid attribute ID";
case AdcDeviceErrorCode::ERROR_RO_ATTR: case AdcDeviceErrorCode::ERROR_RO_ATTR:
return "read-only attribute"; return "read-only attribute";
case AdcDeviceErrorCode::ERROR_WO_ATTR: case AdcDeviceErrorCode::ERROR_WO_ATTR:
@@ -94,6 +96,11 @@ struct AdcDeviceErrorCategory : std::error_category {
} }
}; };
inline std::error_code make_error_code(AdcDeviceErrorCode ec)
{
return std::error_code(static_cast<int>(ec), AdcDeviceErrorCategory::get());
}
template <std::formattable<char> ATTR_ID_T = std::string_view, std::formattable<char> CMD_ID_T = std::string_view> template <std::formattable<char> ATTR_ID_T = std::string_view, std::formattable<char> CMD_ID_T = std::string_view>
class AdcGenericDevice class AdcGenericDevice
@@ -150,13 +157,13 @@ protected:
template <typename VT> template <typename VT>
operator adc_result_t<VT>() operator adc_result_t<VT>()
{ {
auto v = _dev._attrs.template get<VT>(_id); auto const& attr = _dev._attrs.template get<attr_t<VT>>(_id);
if (v) { if (attr) {
return v.value(); return attr.value().getter();
} }
// error // error
if (v.error() == snplib::HeterogenMap<ATTR_ID_T>::ERROR_NO_ELEM) { if (attr.error() == snplib::HeterogenMap<ATTR_ID_T>::ERROR_NO_ELEM) {
return std::unexpected(AdcDeviceErrorCode::ERROR_NO_ATTR_ID); return std::unexpected(AdcDeviceErrorCode::ERROR_NO_ATTR_ID);
} }
@@ -166,10 +173,12 @@ protected:
template <typename VT> template <typename VT>
adc_error_t operator=(VT&& val) adc_error_t operator=(VT&& val)
{ {
auto err = _dev._attrs.set(_id, std::forward<VT>(val)); auto const& attr = _dev._attrs.template get<attr_t<VT>>(_id);
if (err == snplib::HeterogenMap<ATTR_ID_T>::ERROR_OK) { if (attr) {
return AdcDeviceErrorCode::ERROR_OK; return attr.value().setter(std::forward<VT>(val));
} else if (err == snplib::HeterogenMap<ATTR_ID_T>::ERROR_NO_ELEM) { }
if (attr.error() == snplib::HeterogenMap<ATTR_ID_T>::ERROR_NO_ELEM) {
return AdcDeviceErrorCode::ERROR_NO_ATTR_ID; return AdcDeviceErrorCode::ERROR_NO_ATTR_ID;
} else { } else {
return AdcDeviceErrorCode::ERROR_UNKNOWN; return AdcDeviceErrorCode::ERROR_UNKNOWN;
@@ -196,8 +205,8 @@ public:
_commands.emplace(std::move(id), std::forward<ET>(exec_func)); _commands.emplace(std::move(id), std::forward<ET>(exec_func));
} }
template <typename GT, typename ST> template <typename GT, typename ST, typename... VTs>
void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter) void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple<VTs...> = std::tuple())
{ {
// deduce attribute value type // deduce attribute value type
using ret_t = std::invoke_result_t<GT>; using ret_t = std::invoke_result_t<GT>;
@@ -210,6 +219,19 @@ public:
"Invalid return type of the setter!"); "Invalid return type of the setter!");
_attrs.push(std::move(id), attr_t<v_t>{.getter = std::forward<GT>(getter), .setter = std::forward<ST>(setter)}); _attrs.push(std::move(id), attr_t<v_t>{.getter = std::forward<GT>(getter), .setter = std::forward<ST>(setter)});
// if constexpr (sizeof...(VTs)) {
// auto func = [id, this]<size_t I>() {
// using u_t = std::tuple_element_t<I, std::tuple<VTs...>>;
// if constexpr (!requires(u_t u, v_t v) {
// u = v;
// v = u;
// }) {
// static_assert(false, "Invalid user type!");
// }
// _attrs.push(std::move(id), attr_t<u_t>{.getter = []() {}, .setter = []() {}});
// };
// }
} }
adc_error_t operator()(CMD_ID_T id) adc_error_t operator()(CMD_ID_T id)