diff --git a/common/adc_traits.h b/common/adc_traits.h index 4d5a5ff..5a5760c 100644 --- a/common/adc_traits.h +++ b/common/adc_traits.h @@ -78,6 +78,15 @@ struct adc_func_traits { // use of an empty struct here to match std::invoke_result behaivior (at least of GCC) }; +// special case +template <> +struct adc_func_traits { + using ret_t = std::nullptr_t; + using args_t = std::tuple<>; + using arg1_t = std::nullptr_t; + static constexpr size_t arity = 0; +}; + template struct adc_func_traits : adc_func_traits_helper_t { }; diff --git a/common/adc_utils.h b/common/adc_utils.h index 81c0bff..c9585be 100644 --- a/common/adc_utils.h +++ b/common/adc_utils.h @@ -148,6 +148,8 @@ static VT AdcTrivialDeserializer(SerializedT&& s_value) } else { static_assert(false, "TRIVIAL DESERIALIZER: UNSUPPORTED SERIALIZING TYPE!!!"); } + + return VT(); } diff --git a/device/adc_device_attribute.h b/device/adc_device_attribute.h index be2f866..9c11498 100644 --- a/device/adc_device_attribute.h +++ b/device/adc_device_attribute.h @@ -63,52 +63,47 @@ concept adc_attr_convfunc_c = std::is_null_pointer_v || // deduce attribute type from getter and setter functions signatures template -using attr_value_t = +using attr_value_t = std::decay_t< std::conditional_t, std::conditional_t, std::nullptr_t, traits::adc_func_arg1_t>, - traits::adc_retval_t>; + traits::adc_retval_t>>; // deduce attribute internal type from conversional functions signatures template -using attr_internal_t = std::conditional_t< +using attr_internal_t = std::decay_t, std::conditional_t, std::nullptr_t, traits::adc_retval_t>, - traits::adc_retval_t>; + traits::adc_retval_t>>; // deduce user-defined type from conversional functions signatures template -using attr_user_t = std::conditional_t< +using attr_user_t = std::decay_t, std::conditional_t, std::nullptr_t, traits::adc_retval_t>, - traits::adc_retval_t>; + traits::adc_retval_t>>; // attribute serializer function concept template -concept adc_serializer_c = std::invocable && !std::same_as>; +concept adc_serializer_c = + std::is_null_pointer_v || (std::invocable && !std::same_as>); // attribute deserializer function concept -template -concept adc_deserializer_c = std::invocable && !std::same_as>; - - -// a callable and it has exactly one argument -template -concept adc_is_setter = adc_func_traits::arity == 1; - -// a callable with exactly one argument of type VT template -concept adc_is_setter_arg = (adc_func_traits::arity == 1) && std::same_as>; +concept adc_deserializer_c = std::is_null_pointer_v || (traits::adc_func_traits::arity == 1 && + std::convertible_to, VT>); -// a callable with exactly one argument of type VT and it returns a value of type ST -template -concept adc_is_serializer = - (adc_func_traits::arity == 1) && std::same_as> && std::same_as>; +template +using adc_attr_serialized_t = std::decay_t< + std::conditional_t, + std::conditional_t, std::nullptr_t, traits::adc_func_arg1_t>, + traits::adc_retval_t>>; + } // namespace traits @@ -119,7 +114,9 @@ enum class AdcDeviceAttributeErrorCode : int { ERROR_INTERNAL_TYPE_MISMATCH, ERROR_READ_ONLY, ERROR_WRITE_ONLY, - ERROR_INVALID_SERIALIZED_TYPE + ERROR_INVALID_SERIALIZED_TYPE, + ERROR_NO_SERIALIZER, + ERROR_NO_DESERIALIZER }; } // namespace adc @@ -163,6 +160,10 @@ struct AdcDeviceAttributeErrorCategory : public std::error_category { return "device attribute is write-only"; case AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE: return "invalid user-passed serialized type"; + case AdcDeviceAttributeErrorCode::ERROR_NO_SERIALIZER: + return "serializing function was not defined"; + case AdcDeviceAttributeErrorCode::ERROR_NO_DESERIALIZER: + return "deserializing function was not defined"; default: return "UNKNOWN"; } @@ -216,68 +217,63 @@ public: enum AccessType { ReadOnly, WriteOnly, ReadWrite }; - template - constexpr static T DummyGetter() - { - return T(); - } - - - template - constexpr static void DummySetter(const T&) - { - } - - template - constexpr static SerializedT DummySerializer(const T&) - { - return SerializedT(); - } - - template - constexpr static T DummyDeserializer(const SerializedT&) - { - return T(); - } - /* CONSTRUCTORS AND DESTRUCTOR */ - template GT, - typename ValueT = ret_value_t, - std::invocable ST, - std::invocable SRT = + template , + traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), - typename SerializedT = ret_value_t, - std::invocable DSRT = - decltype(utils::AdcDefaultValueConverter<>::deserialize)> - AdcDeviceAttribute(GT&& getter, - ST&& setter, - SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, - DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) + traits::adc_deserializer_c DSRT = + decltype(utils::AdcDefaultValueConverter<>::deserialize)> + AdcDeviceAttribute( + const IdentT& ident, + GT&& getter, + ST&& setter, + SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, + DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) + : _ident(ident), _accessType(AdcDeviceAttribute::ReadWrite) { + static_assert(!std::is_null_pointer_v, "Getter and Setter can not be nullptr simultaneously!!!"); + + using SerializedT = traits::adc_attr_serialized_t; + static_assert(!std::is_null_pointer_v, "Deduced serialized type must not be std::nullptr_t!!!"); + _getterFunc.emplace(this, std::forward(getter)); _setterFunc.emplace(this, std::forward(setter)); + if constexpr (std::is_null_pointer_v) { + _accessType = AdcDeviceAttribute::WriteOnly; + } - _serializerFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(serializer)), this]() { - auto& serializer = std::get<0>(wrapper); + if constexpr (std::is_null_pointer_v) { + _accessType = AdcDeviceAttribute::ReadOnly; + } + + if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { + _serializerFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(serializer)), + this]() { + auto& serializer = std::get<0>(wrapper); - auto val = _getterFunc[this](); + auto val = _getterFunc[this](); - return serializer(val); - }; + return serializer(val); + }; + } - _deserializerFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(deserializer)), - this](const SerializedT& sval) { - auto& deserializer = std::get<0>(wrapper); + if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { + _deserializerFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(deserializer)), + this](const SerializedT& sval) { + auto& deserializer = std::get<0>(wrapper); - ValueT val = deserializer(sval); + ValueT val = deserializer(sval); - _setterFunc[this](val); - }; + _setterFunc[this](val); + }; + } _clearFunc = [this]() { _getterFunc.erase(this); @@ -309,90 +305,77 @@ public: } - template TupleT, - std::invocable<> GT, - typename ValueT = ret_value_t, - std::invocable ST, - std::invocable SRT = + template , + traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), - typename SerializedT = ret_value_t, - std::invocable DSRT = - decltype(utils::AdcDefaultValueConverter<>::deserialize)> - AdcDeviceAttribute(TupleT&&, - GT&& getter, - ST&& setter, - SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, - DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) - : AdcDeviceAttribute(std::forward(getter), + traits::adc_deserializer_c DSRT = + decltype(utils::AdcDefaultValueConverter<>::deserialize)> + AdcDeviceAttribute( + const IdentT& ident, + TupleT&&, + GT&& getter, + ST&& setter, + SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, + DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) + : AdcDeviceAttribute(ident, + std::forward(getter), std::forward(setter), std::forward(serializer), std::forward(deserializer)) { + static_assert(!std::is_null_pointer_v, "Getter and Setter can not be nullptr simultaneously!!!"); + AdcDeviceAttribute::setupTrivialConvertFunc>(); } - // read-only attribute constructor - template GT, + template , - std::invocable SRT = + traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), typename SerializedT = ret_value_t> AdcDeviceAttribute(const IdentT& ident, GT&& getter, SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize) - : AdcDeviceAttribute(ident, - std::forward(getter), - AdcDeviceAttribute::DummySetter, - std::forward(serializer), - AdcDeviceAttribute::DummyDeserializer) + : AdcDeviceAttribute(ident, std::forward(getter), nullptr, std::forward(serializer), nullptr) { - _accessType = ReadOnly; } - template TupleT, - std::invocable<> GT, + template , - std::invocable SRT = + traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), typename SerializedT = ret_value_t> AdcDeviceAttribute(const IdentT& ident, TupleT&&, GT&& getter, SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize) - : AdcDeviceAttribute(ident, - TupleT{}, - std::forward(getter), - AdcDeviceAttribute::DummySetter, - std::forward(serializer), - AdcDeviceAttribute::DummyDeserializer) + : AdcDeviceAttribute(ident, TupleT{}, std::forward(getter), nullptr, std::forward(serializer), nullptr) { - _accessType = ReadOnly; } // write-only attribute constructor - template ST, + template >, typename DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize), typename SerializedT = std::decay_t>> AdcDeviceAttribute(const IdentT& ident, ST&& setter, DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) - : AdcDeviceAttribute(ident, - AdcDeviceAttribute::DummyGetter, - std::forward(setter), - AdcDeviceAttribute::DummySerializer, - std::forward(deserializer)) + : AdcDeviceAttribute(ident, nullptr, std::forward(setter), nullptr, std::forward(deserializer)) { - _accessType = WriteOnly; } - template TupleT, - traits::adc_is_setter<> ST, + template >, typename DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize), typename SerializedT = std::decay_t>> @@ -402,16 +385,14 @@ public: DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) : AdcDeviceAttribute(ident, TupleT{}, - AdcDeviceAttribute::DummyGetter, + nullptr, std::forward(setter), - AdcDeviceAttribute::DummySerializer, + nullptr, std::forward(deserializer)) { - _accessType = WriteOnly; } - AdcDeviceAttribute(const AdcDeviceAttribute& other) { _clearFunc(); @@ -447,37 +428,45 @@ public: AccessType accessType() const { return _accessType; } - template + template AdcDeviceAttribute& addConvertFunc(FromFuncT&& func_from_internal, ToFuncT&& func_to_internal) - requires std::invocable&> && - std::invocable&> { - using value_t = ret_value_t; // it must be internal value type - using user_t = ret_value_t; + // using value_t = ret_value_t; // it must be internal value type + // using user_t = ret_value_t; - _getterFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(func_from_internal)), - this]() { - auto& getter = _getterFunc[this]; - if (getter) { - auto val = getter(); - return std::get<0>(wrapper)(val); // convert from internal type - } - // invalid conversion function signature + using value_t = traits::attr_internal_t; + using user_t = traits::attr_user_t; + + static_assert(!std::is_null_pointer_v, + "Deduced attribute internal type must not be std::nullptr_t!!!"); + static_assert(!std::is_null_pointer_v, "Deduced user-defined type must not be std::nullptr_t!!!"); + + try { + if (_accessType != AdcDeviceAttribute::WriteOnly) { + auto& getter = _getterFunc.at(this); // throw out_of_range if value_t is invalid + + _getterFunc[this] = + [&getter, wrapper = traits::adc_pf_wrapper(std::forward(func_from_internal)), this]() { + auto val = getter(); + return std::get<0>(wrapper)(val); // convert from internal type + }; + } // ignore "from_internal" conversional function for write-only attribute + + + + if (_accessType != AdcDeviceAttribute::ReadOnly) { + auto& setter = _setterFunc.at(this); // throw out_of_range if value_t is invalid + + _setterFunc[this] = [&setter, + wrapper = traits::adc_pf_wrapper(std::forward(func_to_internal)), + this](const user_t& val) { + value_t value = std::get<0>(wrapper)(val); // convert to internal type + setter(value); + }; + } // ignore "to_internal" conversional function for read-only attribute + } catch (const std::out_of_range&) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INTERNAL_TYPE_MISMATCH); - }; - - - _setterFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(func_to_internal)), - this](const user_t& val) { - value_t value = std::get<0>(wrapper)(val); // convert to internal type - auto& setter = _setterFunc[this]; - if (setter) { - setter(value); - } else { - // invalid conversion function signature - throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INTERNAL_TYPE_MISMATCH); - } - }; + } _clearFunc = [prev_clear = _clearFunc, this]() { prev_clear(); @@ -515,16 +504,22 @@ public: using val_t = std::decay_t; - auto getter = _getterFunc[this]; - if (getter) { - return getter(); + try { + return _getterFunc.at(this)(); + } catch (const std::out_of_range&) { + throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); } - throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); + // auto& getter = _getterFunc[this]; + // if (getter) { + // return getter(); + // } + + // throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); } template - AdcDeviceAttribute& operator=(UT&& other) + AdcDeviceAttribute& operator=(UT&& val) { if (_accessType == ReadOnly) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_READ_ONLY); @@ -532,13 +527,19 @@ public: using val_t = std::decay_t; - auto setter = _setterFunc[this]; - if (setter) { - setter(std::forward(other)); - } else { + try { + _setterFunc.at(this)(std::forward(val)); + } catch (const std::out_of_range&) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); } + // auto& setter = _setterFunc[this]; + // if (setter) { + // setter(std::forward(val)); + // } else { + // throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); + // } + return *this; } @@ -577,28 +578,63 @@ public: template SerializedT serialize() { - using s_t = std::decay_t; - - auto& serializer = _serializerFunc[this]; - - if (serializer) { - return serializer(); + if (_accessType == AdcDeviceAttribute::WriteOnly) { + throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_WRITE_ONLY); } - throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE); + using s_t = std::decay_t; + + try { + _serializerFunc.at(this)(); + } catch (const std::out_of_range&) { + throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE); + } catch (const std::bad_function_call&) { // serializer was not defined in ctor! + throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_SERIALIZER); + } + + // auto& serializer = _serializerFunc[this]; + + // if (serializer) { + // return serializer(); + // } + + // throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE); } template - void deserialize(const SerializedT& sval) + AdcDeviceAttribute& deserialize(const SerializedT& sval) { + if (_accessType == AdcDeviceAttribute::ReadOnly) { + throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_READ_ONLY); + } + using s_t = std::decay_t; - auto& deserializer = _deserializerFunc[this]; - if (deserializer) { - deserializer(sval); - } else { + try { + _deserializerFunc.at(this)(sval); + } catch (const std::out_of_range&) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE); + } catch (const std::bad_function_call&) { // deserializer was not defined in ctor! + throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_DESERIALIZER); } + + // auto& deserializer = _deserializerFunc[this]; + // if (deserializer) { + // deserializer(sval); + // } else { + // throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE); + // } + + return *this; + } + + + /* some usefull factory functions */ + + template + static AdcDeviceAttribute makeArithAttr(const IdentT& ident, CtorArgTs... ctor_args) + { + return AdcDeviceAttribute{ident, constants::AdcDefaultTrivialConvTypes, std::forward(ctor_args)...}; } protected: @@ -628,4 +664,5 @@ protected: } }; + } // namespace adc diff --git a/device/adc_device_command.h b/device/adc_device_command.h index cce481d..ac2d771 100644 --- a/device/adc_device_command.h +++ b/device/adc_device_command.h @@ -7,10 +7,9 @@ */ -#include -#include -// #include "../common/adc_value_holder.h" -#include "../common/adc_value.h" +#include +#include "../common/adc_traits.h" + /* @@ -19,76 +18,32 @@ namespace adc { -template + +namespace traits +{ + +template +concept adc_cmd_exec_c = traits::adc_func_traits::arity == 0 && !std::same_as; + +} // namespace traits + + +template class AdcDeviceCommand { protected: IdentT _ident; - std::unique_ptr> _commandArgUptr; - - std::function _execFuncWrapper; - std::function _deserializerWrapper; - - template - constexpr static SerializedT AdcDeviceCommandDummySerializer(const T&) - { - return SerializedT(); - } + std::function _execFunc; public: typedef IdentT ident_t; - typedef SerializedT serialized_t; - template , - typename DeserializerT = decltype(utils::AdcDefaultValueConverter<>::deserialize), - typename ValidatorT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)> - AdcDeviceCommand(const IdentT& ident, - ExecFuncT&& exec_func, - DeserializerT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize, - ValidatorT&& validator = AdcValueHolder::AdcValueHolderDummyValidator) - : _ident(ident), _commandArgUptr() + template + AdcDeviceCommand(const IdentT& ident, ExecFuncT&& exec_func) + : _ident(ident), _execFunc(std::forward(exec_func)) { - using sign_t = traits::adc_func_traits; - - static_assert(sign_t::arity > 1, "COMMAND EXECUTION FUNCTION MUST ACCEPT 0 OR EXACTLY 1 ARGUMENT!!!"); - - if constexpr (sign_t::arity) { // command with argument - using value_t = typename sign_t::arg1_t; - - static_assert(std::predicate, "INVALID TYPE OF VALIDATOR"); - - static_assert(std::invocable, "INVALID TYPE OF DESERIALIZER"); - static_assert(std::is_convertible_v, value_t>, - "INVALID RETURN TYPE OF DESERIALIZER"); - - - auto command_arg = std::shared_ptr(value_t()); - - _commandArgUptr = std::make_unique>( - [command_arg]() { return *command_arg; }, [command_arg](const value_t& value) { *command_arg = value; }, - std::forward(validator)); - - _execFuncWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(exec_func)), this]() { - auto& exec_func = std::get<0>(wrapper); - value_t val = std::any_cast(*_commandArgUptr); - exec_func(val); - }; - - - _deserializerWrapper = - [wrapper = traits::adc_pf_wrapper(std::forward(deserializer))](std::any& val) { - auto& deserializer = std::get<0>(wrapper); - val = std::make_any(deserializer(std::any_cast(val))); - }; - - // setup only convert-to-native-value function (deserializer) - _commandArgUptr->addConvertFunc(std::forward(deserializer), []() {}); - } else { // command without argument (ignore deserializer and validator) - _execFuncWrapper = std::forward(exec_func); - } } @@ -100,24 +55,7 @@ public: IdentT ident() const { return ident; } - template - void operator()(const ValueT& value) - { - if (_commandArgUptr) { // command with argument - *_commandArgUptr = value; - } - _execFuncWrapper(); - } - - - void operator()() - { - if (_commandArgUptr) { // command with argument - throw 1; - } - - _execFuncWrapper(); - } + void operator()() { _execFunc(); } }; diff --git a/tests/adc_devattr_test.cpp b/tests/adc_devattr_test.cpp index 767dbd4..0b2d8c5 100644 --- a/tests/adc_devattr_test.cpp +++ b/tests/adc_devattr_test.cpp @@ -32,15 +32,28 @@ TEST_CASE("[ADC DEVICE ATTRIBUTE]") using attr_t = AdcDeviceAttribute; - attr_t attr("ATTR_A", adc::constants::AdcDefaultTrivialConvTypes, vv::getter, vv::setter); + std::string_view id{"ATTR_A"}; + + // attr_t attr(id, adc::constants::AdcDefaultTrivialConvTypes, vv::getter, vv::setter); + attr_t attr("id", adc::constants::AdcDefaultTrivialConvTypes, vv::getter, vv::setter); attr = 10.7; av = attr; std::cout << "ATTR = " << av << "\n"; - // std::cout << "ATTR = " << (unsigned)attr << "\n"; + std::cout << "ATTR = " << (unsigned)attr << "\n"; + // attr_t aw("ATTR_WO", nullptr, vv::setter, nullptr); attr_t aw("ATTR_WO", adc::constants::AdcDefaultTrivialConvTypes, vv::setter); + // attr_t aw(id, adc::constants::AdcDefaultTrivialConvTypes, vv::setter); std::cout << "ACC_TYPE: " << aw.accessType() << "\n"; + // av = aw; + aw = 4534.6588; + + // attr_t ar("ATTR_RO", adc::constants::AdcDefaultTrivialConvTypes, vv::getter); + auto ar = attr_t::makeArithAttr("ATTR_RO", vv::getter); + std::cout << "ACC_TYPE: " << ar.accessType() << "\n"; + + std::cout << "ATTR_RO = " << (double)ar << "\n"; }