diff --git a/CMakeLists.txt b/CMakeLists.txt index 24c7dd6..65f1db6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,9 @@ if (BUILD_TESTS) set(VALUEHOLDER_TEST_APP adc_valueholder_test) add_executable(${VALUEHOLDER_TEST_APP} tests/adc_valueholder_test.cpp) + set(DEVATTR_TEST_APP adc_devattr_test) + add_executable(${DEVATTR_TEST_APP} tests/adc_devattr_test.cpp) + if (NOT doctest_FOUND) include(FetchContent) FetchContent_Declare( diff --git a/common/adc_utils.h b/common/adc_utils.h index 0722d88..81c0bff 100644 --- a/common/adc_utils.h +++ b/common/adc_utils.h @@ -36,7 +36,9 @@ static ValueT AdcFromChars(R&& range) #ifdef _LIBCPP_VERSION // clang's libc++ does not have floating-point overloads for std::from_chars if constexpr (traits::adc_is_any_v) { #else - if constexpr (traits::adc_is_any_of_v) { + if constexpr (traits::adc_is_any_of_v) { #endif v_t v; diff --git a/common/adc_value.h b/common/adc_value.h index 19e97cd..58f2c6b 100644 --- a/common/adc_value.h +++ b/common/adc_value.h @@ -47,7 +47,7 @@ namespace adc struct AdcValueHolderErrorCategory : public std::error_category { AdcValueHolderErrorCategory() : std::error_category() {} - const char* name() const noexcept { return "DEVA_DEVICE_ATTRIBUTE"; } + const char* name() const noexcept { return "ADC_VALUEHOLDER_CATEGORY"; } std::string message(int ec) const { @@ -404,6 +404,8 @@ protected: } public: + typedef SerializedT serialized_t; + /* CONSTRUCTORS AND DESTRUCTOR */ template +class AdcDeviceAttribute : public AdcSerializingValueHolder +{ + using base_t = AdcSerializingValueHolder; + + template + using ret_value_t = base_t::template ret_value_t; + +public: + typedef IdentT ident_t; + typedef SerializedT serialized_t; + + enum AccessType { ReadOnly, WriteOnly, ReadWrite }; + + template + constexpr static T DummyGetter() + { + return std::declval(); + } + + + template + constexpr static void DummySetter(const T&) + { + } + + template + constexpr static SerializedT DummySerializer(const T&) + { + return std::declval(); + } + + template + constexpr static T DummyDeserializer(const SerializedT&) + { + return std::declval(); + } + + + /* CONSTRUCTORS AND DESTRUCTOR */ + + // general read-write attribute constructor + template , + typename VT = decltype(AdcValueHolder::AdcValueHolderDummyValidator), + typename SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), + typename DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize)> + AdcDeviceAttribute(const IdentT& ident, + AccessType access_type, + GT&& getter, + ST&& setter, + VT&& validator = AdcValueHolder::AdcValueHolderDummyValidator, + SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, + DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) + requires std::invocable && std::invocable && std::predicate && + std::invocable && std::invocable + : base_t(std::forward(getter), + std::forward(setter), + std::forward(validator), + std::forward(serializer), + std::forward(deserializer)), + _ident(ident), + _accessType(access_type) + { + } + + + // read-only attribute constructor + template , + typename SRT = decltype(utils::AdcDefaultValueConverter<>::serialize)> + AdcDeviceAttribute(const IdentT& ident, + GT&& getter, + SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize) + requires std::invocable && std::invocable + : AdcDeviceAttribute(ident, + ReadOnly, + std::forward(getter), + AdcDeviceAttribute::DummySetter, + AdcValueHolder::AdcValueHolderDummyValidator, + std::forward(serializer), + AdcDeviceAttribute::DummyDeserializer) + { + } + + + // write-only attribute constructor + template >, + typename DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize)> + AdcDeviceAttribute(const IdentT& ident, + ST&& setter, + std::predicate auto&& validator, + DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) + requires std::invocable + : AdcDeviceAttribute(ident, + WriteOnly, + AdcDeviceAttribute::DummyGetter, + std::forward(setter), + std::forward(validator), + AdcDeviceAttribute::DummySerializer, + std::forward(deserializer)) + { + } + + + // constructor of attribute with trivially casting type converters + template + AdcDeviceAttribute(const std::tuple&, Ts&&... ctor_args) + : AdcDeviceAttribute(std::forward(ctor_args)...) + { + } + + virtual ~AdcDeviceAttribute() = default; + + IdentT ident() const { return _ident; } + + AccessType accessType() const { return _accessType; } + + using base_t::operator=; + +protected: + IdentT _ident; + AccessType _accessType; +}; + +} // namespace adc diff --git a/tests/adc_devattr_test.cpp b/tests/adc_devattr_test.cpp new file mode 100644 index 0000000..36c7a41 --- /dev/null +++ b/tests/adc_devattr_test.cpp @@ -0,0 +1,44 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include +#include + + +#include "../device/adc_device_attribute.h" + +using namespace adc; + +template +struct V { + static T getter() { return _v; } + static void setter(const T& v) { _v = v; } + + static bool validator(const T& v) + { + if (v < 1) + return false; + else + return true; + } + +private: + inline static T _v = 1; +}; + + +TEST_CASE("[ADC DEVICE ATTRIBUTE]") +{ + double av = -10; + using vv = V; + + using attr_t = AdcDeviceAttribute; + + // attr_t attr(AdcValueHolder::_defaultTrivialConvTypes, "ATTR_A", attr_t::ReadWrite, vv::getter, vv::setter, + // vv::validator); + attr_t attr("ATTR_A", attr_t::ReadWrite, vv::getter, vv::setter, vv::validator); + + // attr = 10.7; + // av = attr; + + // std::cout << "ATTR = " << av << "\n"; + std::cout << "ATTR = " << (unsigned)attr << "\n"; +}