From bdaaaab559cd75c6c601673f5e51d8752ba45146 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Wed, 15 Jul 2026 15:52:10 +0300 Subject: [PATCH] add ability of authomatic attribute-value type conversion (for user given types!) --- examples/device_exam.cpp | 61 +++++++++++++++++++---------- include/adclib/adclib_device.h | 71 ++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 27 deletions(-) diff --git a/examples/device_exam.cpp b/examples/device_exam.cpp index 3eb5663..ea1bde9 100644 --- a/examples/device_exam.cpp +++ b/examples/device_exam.cpp @@ -6,50 +6,71 @@ using namespace adc; int main() { + std::string id1 = "1", id2 = "2"; + int i = 10; double d = 8.1; std::string s{"dwedjkwlk"}; AdcGenericDevice<> dev("DEV#1"); + std::println("add RW-attr with id='{}' (val={})", id1, i); dev.addAttr( - "1", [&i]() -> adc_result_t { return i; }, + id1, [&i]() -> adc_result_t { return i; }, [&i](int ii) -> adc_error_t { i = ii; return AdcDeviceErrorCode::ERROR_OK; - }); + }, + std::tuple{}); - dev.addAttr("2", [&d]() -> adc_result_t { return d; }, nullptr); + std::println("add RO-attr with id='{}' (val={})", id2, d); + dev.addAttr(id2, [&d]() -> adc_result_t { return d; }, nullptr); - adc_result_t ri = dev["1"]; + std::print("get '{}'-attr value as native int:\t", id1); + adc_result_t ri = dev[id1]; if (ri) { - std::println("dev[1] = {}", ri.value()); + std::println("dev[{}] = {}", id1, ri.value()); } else { - std::println("cannot get dev[1] as int: {}", ri.error().message()); + std::println("cannot get dev[{}] as int: {}", id1, ri.error().message()); } - auto err = dev["1"] = 77; + int ii = 77; + std::print("set '{}'-attr value to {} as native int:\t", id1, ii); + auto err = dev[id1] = ii; if (err) { - std::println("cannot set dev[1] as int: {}", err.message()); + std::println("cannot set dev[{}] as int: {}", id1, err.message()); + } else { + std::println("OK"); } - adc_result_t rd = dev["1"]; + std::print("get '{}'-attr value as double:\t", id1); + adc_result_t rd = dev[id1]; if (rd) { - std::println("dev[1] = {}", rd.value()); + std::println("dev[{}] = {}", id1, rd.value()); } else { - std::println("cannot get dev[1] as double: {}", rd.error().message()); + std::println("cannot get dev[{}] as double: {}", id1, rd.error().message()); } - ri = dev["1"]; - if (ri) { - std::println("dev[1] = {}", ri.value()); - } else { - std::println("cannot get dev[1] as int: {}", ri.error().message()); - } - - err = dev["2"] = 0.29817; + double dd = 33.333; + std::print("set '{}'-attr value to {} as double:\t", id1, dd); + err = dev[id1] = dd; if (err) { - std::println("cannot set dev[2] as double: {}", err.message()); + std::println("cannot set dev[{}] as double: {}", id1, err.message()); + } else { + std::println("OK"); + } + + std::print("get '{}'-attr value as native int:\t", id1); + ri = dev[id1]; + if (ri) { + std::println("dev[{}] = {}", id1, ri.value()); + } else { + std::println("cannot get dev[{}] as int: {}", id1, ri.error().message()); + } + + err = dev[id2] = 0.29817; + if (err) { + std::println("cannot set dev[{}] as double: {}", id2, err.message()); } return 0; diff --git a/include/adclib/adclib_device.h b/include/adclib/adclib_device.h index 2fe3ad2..b8530b8 100644 --- a/include/adclib/adclib_device.h +++ b/include/adclib/adclib_device.h @@ -133,8 +133,49 @@ class AdcGenericDevice protected: template struct attr_t { - std::function()> getter; - std::function setter; + std::function()> getter{}; + std::function setter{}; + + template + requires(requires(VT v, UT u) { v = u; } && !std::same_as) + attr_t& operator=(attr_t const& other) + { + if (other.getter) { + getter = [&other]() -> adc_result_t { + auto val = other.getter(); + if (val) { + return static_cast(val.value()); + } + + return std::unexpected(val.error()); + }; + } else { // write-only attribute + getter = nullptr; + } + + if (other.setter) { + setter = [&other](VT const& v) { return other.setter(static_cast(v)); }; + } else { // read-only attribute + setter = nullptr; + } + + return *this; + } + + template + requires requires(VT v, UT u) { v = u; } + operator attr_t() const + { + return attr_t{.getter = [this]() -> adc_result_t { + auto val = getter(); + if (val) { + return static_cast(val.value()); + } else { + return std::unexpected(val.error()); + } + }, + .setter = [this](UT const& u) { return setter(static_cast(u)); }}; + } adc_error_t serialize(snplib::snplib_output_char_range_c auto& output, snplib::snplib_serialization_params_c auto const& params) @@ -200,7 +241,7 @@ protected: template adc_error_t operator=(VT&& val) { - auto attr = _dev._attrs.template get>>(_id); + auto attr = _dev._attrs.template get>>(_id); if (attr) { if (attr.value().setter) { return attr.value().setter(std::forward(val)); @@ -228,6 +269,22 @@ protected: snplib::HeterogenMap _attrs{}; public: + static constexpr std::tuple + arithmetic_t{}; + typedef DEV_ID_T device_id_t; typedef ATTR_ID_T attr_id_t; typedef CMD_ID_T cmd_id_t; @@ -255,9 +312,8 @@ public: _commands.emplace(std::move(id), std::forward(exec_func)); } - // template - template - void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter) + template + void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple = std::tuple<>{}) { using v_t = snplib_attr_value_deduced_t; static_assert(!std::is_void_v, "Getter and setter cannot be nullptr_t at the same time!"); @@ -266,7 +322,8 @@ public: static_assert(std::invocable, "Invalid setter argument type!"); } - _attrs.push(std::move(id), attr_t{.getter = std::forward(getter), .setter = std::forward(setter)}); + _attrs.push(std::move(id), attr_t{.getter = std::forward(getter), .setter = std::forward(setter)}, + std::tuple...>{}); } adc_error_t operator()(CMD_ID_T id)