From 366d4e05b0ffa9fa8edc72e5d072335ff4eada15 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Sat, 25 May 2024 20:58:15 +0300 Subject: [PATCH] start network-related part --- CMakeLists.txt | 22 +++-- common/adc_traits.h | 4 +- net/adc_netmessage.h | 230 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+), 12 deletions(-) create mode 100644 net/adc_netmessage.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bc65c3..2ce1733 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(ADC_COMMON_HEADERS common/adc_traits.h - common/adc_value_holder.h - common/adc_value.h - common/adc_valholder.h) + common/adc_utils.h + # common/adc_value_holder.h + # common/adc_value.h + # common/adc_valholder.h +) set(ADC_DEVICE_HEADERS device/adc_device_attribute.h @@ -24,8 +26,8 @@ option(BUILD_TESTS "Build tests" ON) if (BUILD_TESTS) find_package(doctest) - set(VALUEHOLDER_TEST_APP adc_valueholder_test) - add_executable(${VALUEHOLDER_TEST_APP} tests/adc_valueholder_test.cpp) + # 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) @@ -40,17 +42,17 @@ if (BUILD_TESTS) FetchContent_MakeAvailable(doctest) endif() - target_link_libraries(${VALUEHOLDER_TEST_APP} PRIVATE doctest::doctest) + # target_link_libraries(${VALUEHOLDER_TEST_APP} PRIVATE doctest::doctest) + target_link_libraries(${DEVATTR_TEST_APP} PRIVATE doctest::doctest) include(CTest) - add_test(VALUE_HOLDER ${VALUEHOLDER_TEST_APP}) + # add_test(VALUE_HOLDER ${VALUEHOLDER_TEST_APP}) + add_test(VALUE_HOLDER ${DEVATTR_TEST_APP}) enable_testing() endif(BUILD_TESTS) include(GNUInstallDirs) -add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS} - common/adc_traits.h - common/adc_utils.h) +add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS}) target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) # target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO) target_include_directories( diff --git a/common/adc_traits.h b/common/adc_traits.h index 5a5760c..f1ac9fe 100644 --- a/common/adc_traits.h +++ b/common/adc_traits.h @@ -37,8 +37,8 @@ concept adc_output_char_range = std::ranges::output_range; // range of char/const char template -concept adc_input_char_range = std::ranges::input_range; -// concept adc_input_char_range = std::ranges::input_range; +concept adc_input_char_range = + std::ranges::input_range && std::is_same_v>, CharT>; // deduce returned type of callable diff --git a/net/adc_netmessage.h b/net/adc_netmessage.h new file mode 100644 index 0000000..45cc6f1 --- /dev/null +++ b/net/adc_netmessage.h @@ -0,0 +1,230 @@ +#pragma once + +#include + +#include "../common/adc_traits.h" +#include "../common/adc_utils.h" + + +/* + +ABSTRACT DEVICE COMPONENTS LIBRARY + + */ + + + +/* GENERIC NETWORK MESSAGE CLASS */ + +namespace adc +{ + + +namespace traits +{ + +// from message view to byte converter concept +template +concept adc_to_bytes_func_c = std::invocable && !std::convertible_to, BT>; + + +// from bytes to message view converter concept +template +concept adc_from_bytes_func_c = std::invocable && std::convertible_to, VT>; + + +struct AdcTheSameTypeTag { +}; + +} // namespace traits + + +template ByteStorageT, + std::ranges::output_range> StorageSeqT> +class AdcNetMessageInterface +{ +protected: + ByteStorageT _byteStorage; + StorageSeqT _storageSequence; + + AdcNetMessageInterface() = default; + + template + AdcNetMessageInterface(const T& v, const Ts&... vs) : AdcNetMessageInterface() + { + appendBytes(v, vs...); + } + + virtual ~AdcNetMessageInterface() = default; + + AdcNetMessageInterface(const AdcNetMessageInterface&) = default; + AdcNetMessageInterface(AdcNetMessageInterface&&) = default; + + AdcNetMessageInterface& operator=(const AdcNetMessageInterface&) = default; + AdcNetMessageInterface& operator=(AdcNetMessageInterface&&) = default; + + template + void appendBytes(const T& v, const Ts&... vs) + { + if constexpr (std::is_array_v>) { + appendBytes(std::string_view(v), vs...); + } else { + std::ranges::copy(v, std::back_inserter(_byteStorage)); + } + if constexpr (sizeof...(Ts)) { + appendBytes(vs...); + } + } + + template + void setBytes(const T& v, const Ts&... vs) + { + _byteStorage = ByteStorageT(); + appendBytes(v, vs...); + } + + + template + void setBytes(IterT begin, IterT end) + { + _byteStorage = ByteStorageT(begin, end); + } + + template + void appendBytes(IterT begin, IterT end) + { + std::copy(begin, end, std::back_inserter(_byteStorage)); + } + +public: + typedef ByteStorageT byte_storage_t; + typedef StorageSeqT storage_seq_t; + + virtual size_t byteSize() + { + auto v = _storageSequence | + std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) | + std::views::join; + + return std::ranges::distance(v.begin(), v.end()); + } + + + virtual ByteStorageT bytes() + { + auto v = _storageSequence | + std::views::transform([](const auto& el) -> const ByteStorageT& { return el.get(); }) | + std::views::join; + + return ByteStorageT{v.begin(), v.end()}; + }; + + virtual const StorageSeqT& storageSeq() = 0; +}; + + + +template ByteStorageT = std::vector, + typename MessageViewT = traits::AdcTheSameTypeTag> +class AdcGenericNetMessage + : public AdcNetMessageInterface, 1>> +{ + using base_t = AdcNetMessageInterface, 1>>; + +public: + using typename base_t::byte_storage_t; + using typename base_t::storage_seq_t; + + using message_view_t = + std::conditional_t, ByteStorageT, MessageViewT>; + + AdcGenericNetMessage() = default; + + template T, + traits::adc_to_bytes_func_c CONVT = + decltype(utils::AdcDefaultValueConverter<>::serialize)> + AdcGenericNetMessage(T&& v, CONVT&& conv_func = utils::AdcDefaultValueConverter<>::serialize) + : AdcGenericNetMessage() + { + setMessage(std::forward(v), std::forward(conv_func)); + } + + + virtual ~AdcGenericNetMessage() = default; + + template T, + traits::adc_to_bytes_func_c CONVT = + decltype(utils::AdcDefaultValueConverter<>::serialize)> + void setMessage(T&& v, CONVT&& conv_func = utils::AdcDefaultValueConverter<>::serialize) + { + if constexpr (std::is_same_v) { + this->setBytes(std::forward(v)); + } else { + _messageView(std::forward(v)); + this->_byteStorage = std::forward(conv_func)(_messageView); + } + } + + + message_view_t messageView() const + { + if constexpr (std::is_same_v) { + return this->_byteStorage; + } else { + return _messageView; + } + } + + + const storage_seq_t& storageSeq() override + { + this->_storageSequence[0] = this->_byteStorage; + + return this->_storageSequence; + }; + + // factory function + + template CONVT = + decltype(utils::AdcDefaultValueConverter<>::deserialize)> + static AdcGenericNetMessage fromBytes( + BT&& bytes, + CONVT&& conv_func = utils::AdcDefaultValueConverter<>::deserialize) + { + AdcGenericNetMessage msg; + msg.setBytes(std::forward(bytes)); + + if constexpr (!std::is_same_v) { + msg._messageView = conv_func(msg._byteStorage); + } + + return msg; + } + + + template CONVT = + decltype(utils::AdcDefaultValueConverter<>::deserialize)> + static AdcGenericNetMessage fromBytes( + IterT begin, + IterT end, + CONVT&& conv_func = utils::AdcDefaultValueConverter<>::deserialize) + { + AdcGenericNetMessage msg; + msg.setBytes(begin, end); + + if constexpr (!std::is_same_v) { + msg._messageView = conv_func(msg._byteStorage); + } + + return msg; + } + +protected: + MessageViewT _messageView; +}; + + + +} // namespace adc