diff --git a/examples/device_exam.cpp b/examples/device_exam.cpp index 5e46edd..73ff9fb 100644 --- a/examples/device_exam.cpp +++ b/examples/device_exam.cpp @@ -20,6 +20,8 @@ int main() }, std::tuple{}); + dev.addAttr("2", [&d]() -> adc_result_t { return d; }, nullptr); + adc_result_t ri = dev["1"]; if (ri) { std::println("dev[1] = {}", ri.value()); @@ -39,5 +41,17 @@ int main() std::println("cannot get dev[1] as double: {}", 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; + if (err) { + std::println("cannot set dev[2] as double: {}", err.message()); + } + return 0; } \ No newline at end of file diff --git a/include/adclib/adclib_device.h b/include/adclib/adclib_device.h index e07f45e..1b1dda8 100644 --- a/include/adclib/adclib_device.h +++ b/include/adclib/adclib_device.h @@ -13,7 +13,7 @@ #include -// #include +#include #include #include @@ -102,6 +102,29 @@ inline std::error_code make_error_code(AdcDeviceErrorCode ec) } +namespace details +{ + +template +concept snplib_getter_c = std::same_as || requires(T t) { + { t() } -> adc_result_c; +}; + +template +concept snplib_setter_c = + std::same_as || (snplib::snplib_callable_c && (snplib::snplib_func_traits_t::arity >= 1) && + std::same_as::ret_t>); + + +// deduce value type from getter and setter +template +using snplib_attr_value_deduced_t = + std::conditional_t, + std::conditional_t, void, snplib::snplib_func_arg1_t>, + typename std::invoke_result_t::value_type>; + +} // namespace details + template ATTR_ID_T = std::string_view, std::formattable CMD_ID_T = std::string_view> class AdcGenericDevice { @@ -159,7 +182,11 @@ protected: { auto const& attr = _dev._attrs.template get>(_id); if (attr) { - return attr.value().getter(); + if (attr.value().getter) { + return attr.value().getter(); + } + + return std::unexpected(AdcDeviceErrorCode::ERROR_WO_ATTR); } // error @@ -175,7 +202,11 @@ protected: { auto const& attr = _dev._attrs.template get>(_id); if (attr) { - return attr.value().setter(std::forward(val)); + if (attr.value().setter) { + return attr.value().setter(std::forward(val)); + } + + return AdcDeviceErrorCode::ERROR_RO_ATTR; } if (attr.error() == snplib::HeterogenMap::ERROR_NO_ELEM) { @@ -197,6 +228,8 @@ public: typedef ATTR_ID_T attr_id_t; typedef CMD_ID_T cmd_id_t; + enum AttrAccessType { ATTR_ACCESS_RW, ATTR_ACCESS_RO, ATTR_ACCESS_WO }; + AdcGenericDevice() {} template @@ -205,18 +238,30 @@ public: _commands.emplace(std::move(id), std::forward(exec_func)); } - template + // template + template void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple = std::tuple()) { - // deduce attribute value type - using ret_t = std::invoke_result_t; - using v_t = typename ret_t::value_type; + // static_assert(!(std::is_null_pointer_v && std::is_null_pointer_v), + // "Getter and setter cannot be nullptr_t at the same time!"); - static_assert(adc_result_c, "Invalid return type of the getter!"); + // // deduce attribute value type + // using ret_t = std::invoke_result_t; - static_assert(std::invocable, "Invalid setter type!"); - static_assert(std::convertible_to, adc_error_t>, - "Invalid return type of the setter!"); + // static_assert(adc_result_c, "Invalid return type of the getter!"); + + // using v_t = typename ret_t::value_type; + + // static_assert(std::invocable, "Invalid setter type!"); + // static_assert(std::convertible_to, adc_error_t>, + // "Invalid return type of the setter!"); + + using v_t = details::snplib_attr_value_deduced_t; + static_assert(!std::is_void_v, "Getter and setter cannot be nullptr_t at the same time!"); + + if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { + static_assert(std::invocable, "Invalid setter argument type!"); + } _attrs.push(std::move(id), attr_t{.getter = std::forward(getter), .setter = std::forward(setter)}); @@ -229,7 +274,22 @@ public: // }) { // static_assert(false, "Invalid user type!"); // } - // _attrs.push(std::move(id), attr_t{.getter = []() {}, .setter = []() {}}); + + // if constexpr (!std::same_as) { + // _attrs.push(std::move(id), attr_t{.getter = [id, this]() -> adc_result_t { + // auto const& attr = _attrs.template + // get>(id); if (attr) { + // adc_result_t v = attr.getter(); + // if (v) { + // return + // adc_result_t(static_cast(v.value())); + // } + // } + + // return AdcDeviceErrorCode::ERROR_UNKNOWN; + // }, + // .setter = []() {}}); + // } // }; // } } @@ -243,20 +303,22 @@ public: return AdcDeviceErrorCode::ERROR_NO_CMD_ID; } + auto operator[](ATTR_ID_T id) + { + return attr_proxy_t{*this, std::move(id)}; + } + template adc_result_t attr(ATTR_ID_T id) { + return attr_proxy_t{*this, std::move(id)}; } template adc_error_t attr(ATTR_ID_T id, VT const& v) { - } - - auto operator[](ATTR_ID_T id) - { - return attr_proxy_t{*this, std::move(id)}; + return attr_proxy_t{*this, std::move(id)} = v; } };