start network-related part
This commit is contained in:
parent
1c79026a34
commit
366d4e05b0
@ -9,9 +9,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
|
|
||||||
set(ADC_COMMON_HEADERS
|
set(ADC_COMMON_HEADERS
|
||||||
common/adc_traits.h
|
common/adc_traits.h
|
||||||
common/adc_value_holder.h
|
common/adc_utils.h
|
||||||
common/adc_value.h
|
# common/adc_value_holder.h
|
||||||
common/adc_valholder.h)
|
# common/adc_value.h
|
||||||
|
# common/adc_valholder.h
|
||||||
|
)
|
||||||
|
|
||||||
set(ADC_DEVICE_HEADERS
|
set(ADC_DEVICE_HEADERS
|
||||||
device/adc_device_attribute.h
|
device/adc_device_attribute.h
|
||||||
@ -24,8 +26,8 @@ option(BUILD_TESTS "Build tests" ON)
|
|||||||
if (BUILD_TESTS)
|
if (BUILD_TESTS)
|
||||||
find_package(doctest)
|
find_package(doctest)
|
||||||
|
|
||||||
set(VALUEHOLDER_TEST_APP adc_valueholder_test)
|
# set(VALUEHOLDER_TEST_APP adc_valueholder_test)
|
||||||
add_executable(${VALUEHOLDER_TEST_APP} tests/adc_valueholder_test.cpp)
|
# add_executable(${VALUEHOLDER_TEST_APP} tests/adc_valueholder_test.cpp)
|
||||||
|
|
||||||
set(DEVATTR_TEST_APP adc_devattr_test)
|
set(DEVATTR_TEST_APP adc_devattr_test)
|
||||||
add_executable(${DEVATTR_TEST_APP} tests/adc_devattr_test.cpp)
|
add_executable(${DEVATTR_TEST_APP} tests/adc_devattr_test.cpp)
|
||||||
@ -40,17 +42,17 @@ if (BUILD_TESTS)
|
|||||||
FetchContent_MakeAvailable(doctest)
|
FetchContent_MakeAvailable(doctest)
|
||||||
endif()
|
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)
|
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()
|
enable_testing()
|
||||||
endif(BUILD_TESTS)
|
endif(BUILD_TESTS)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS}
|
add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS})
|
||||||
common/adc_traits.h
|
|
||||||
common/adc_utils.h)
|
|
||||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
|
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
|
||||||
# target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO)
|
# target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO)
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
|
|||||||
@ -37,8 +37,8 @@ concept adc_output_char_range = std::ranges::output_range<R, CharT>;
|
|||||||
|
|
||||||
// range of char/const char
|
// range of char/const char
|
||||||
template <typename R, typename CharT = char>
|
template <typename R, typename CharT = char>
|
||||||
concept adc_input_char_range = std::ranges::input_range<R>;
|
concept adc_input_char_range =
|
||||||
// concept adc_input_char_range = std::ranges::input_range<CharT>;
|
std::ranges::input_range<R> && std::is_same_v<std::remove_cv_t<std::ranges::range_value_t<R>>, CharT>;
|
||||||
|
|
||||||
|
|
||||||
// deduce returned type of callable
|
// deduce returned type of callable
|
||||||
|
|||||||
230
net/adc_netmessage.h
Normal file
230
net/adc_netmessage.h
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
#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 <typename T, typename BT, typename VT>
|
||||||
|
concept adc_to_bytes_func_c = std::invocable<T, const VT&> && !std::convertible_to<traits::adc_retval_t<T>, BT>;
|
||||||
|
|
||||||
|
|
||||||
|
// from bytes to message view converter concept
|
||||||
|
template <typename T, typename BT, typename VT>
|
||||||
|
concept adc_from_bytes_func_c = std::invocable<T, const BT&> && std::convertible_to<traits::adc_retval_t<T>, VT>;
|
||||||
|
|
||||||
|
|
||||||
|
struct AdcTheSameTypeTag {
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace traits
|
||||||
|
|
||||||
|
|
||||||
|
template <std::ranges::output_range<char> ByteStorageT,
|
||||||
|
std::ranges::output_range<std::reference_wrapper<const ByteStorageT>> StorageSeqT>
|
||||||
|
class AdcNetMessageInterface
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ByteStorageT _byteStorage;
|
||||||
|
StorageSeqT _storageSequence;
|
||||||
|
|
||||||
|
AdcNetMessageInterface() = default;
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range T, traits::adc_input_char_range... Ts>
|
||||||
|
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 <traits::adc_input_char_range T, traits::adc_input_char_range... Ts>
|
||||||
|
void appendBytes(const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) {
|
||||||
|
appendBytes(std::string_view(v), vs...);
|
||||||
|
} else {
|
||||||
|
std::ranges::copy(v, std::back_inserter(_byteStorage));
|
||||||
|
}
|
||||||
|
if constexpr (sizeof...(Ts)) {
|
||||||
|
appendBytes(vs...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range T, traits::adc_input_char_range... Ts>
|
||||||
|
void setBytes(const T& v, const Ts&... vs)
|
||||||
|
{
|
||||||
|
_byteStorage = ByteStorageT();
|
||||||
|
appendBytes(v, vs...);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IterT>
|
||||||
|
void setBytes(IterT begin, IterT end)
|
||||||
|
{
|
||||||
|
_byteStorage = ByteStorageT(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::input_iterator IterT>
|
||||||
|
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 <std::ranges::output_range<char> ByteStorageT = std::vector<char>,
|
||||||
|
typename MessageViewT = traits::AdcTheSameTypeTag>
|
||||||
|
class AdcGenericNetMessage
|
||||||
|
: public AdcNetMessageInterface<ByteStorageT, std::array<std::reference_wrapper<const ByteStorageT>, 1>>
|
||||||
|
{
|
||||||
|
using base_t = AdcNetMessageInterface<ByteStorageT, std::array<std::reference_wrapper<const ByteStorageT>, 1>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using typename base_t::byte_storage_t;
|
||||||
|
using typename base_t::storage_seq_t;
|
||||||
|
|
||||||
|
using message_view_t =
|
||||||
|
std::conditional_t<std::is_same_v<MessageViewT, traits::AdcTheSameTypeTag>, ByteStorageT, MessageViewT>;
|
||||||
|
|
||||||
|
AdcGenericNetMessage() = default;
|
||||||
|
|
||||||
|
template <std::convertible_to<MessageViewT> T,
|
||||||
|
traits::adc_to_bytes_func_c<ByteStorageT, MessageViewT> CONVT =
|
||||||
|
decltype(utils::AdcDefaultValueConverter<>::serialize<ByteStorageT, T>)>
|
||||||
|
AdcGenericNetMessage(T&& v, CONVT&& conv_func = utils::AdcDefaultValueConverter<>::serialize<ByteStorageT, T>)
|
||||||
|
: AdcGenericNetMessage()
|
||||||
|
{
|
||||||
|
setMessage(std::forward<T>(v), std::forward<CONVT>(conv_func));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~AdcGenericNetMessage() = default;
|
||||||
|
|
||||||
|
template <std::convertible_to<MessageViewT> T,
|
||||||
|
traits::adc_to_bytes_func_c<ByteStorageT, message_view_t> CONVT =
|
||||||
|
decltype(utils::AdcDefaultValueConverter<>::serialize<ByteStorageT, T>)>
|
||||||
|
void setMessage(T&& v, CONVT&& conv_func = utils::AdcDefaultValueConverter<>::serialize<ByteStorageT, T>)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<MessageViewT, traits::AdcTheSameTypeTag>) {
|
||||||
|
this->setBytes(std::forward<T>(v));
|
||||||
|
} else {
|
||||||
|
_messageView(std::forward<T>(v));
|
||||||
|
this->_byteStorage = std::forward<CONVT>(conv_func)(_messageView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message_view_t messageView() const
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<MessageViewT, traits::AdcTheSameTypeTag>) {
|
||||||
|
return this->_byteStorage;
|
||||||
|
} else {
|
||||||
|
return _messageView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const storage_seq_t& storageSeq() override
|
||||||
|
{
|
||||||
|
this->_storageSequence[0] = this->_byteStorage;
|
||||||
|
|
||||||
|
return this->_storageSequence;
|
||||||
|
};
|
||||||
|
|
||||||
|
// factory function
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range BT,
|
||||||
|
traits::adc_from_bytes_func_c<ByteStorageT, message_view_t> CONVT =
|
||||||
|
decltype(utils::AdcDefaultValueConverter<>::deserialize<message_view_t, ByteStorageT>)>
|
||||||
|
static AdcGenericNetMessage fromBytes(
|
||||||
|
BT&& bytes,
|
||||||
|
CONVT&& conv_func = utils::AdcDefaultValueConverter<>::deserialize<message_view_t, ByteStorageT>)
|
||||||
|
{
|
||||||
|
AdcGenericNetMessage msg;
|
||||||
|
msg.setBytes(std::forward<BT>(bytes));
|
||||||
|
|
||||||
|
if constexpr (!std::is_same_v<MessageViewT, traits::AdcTheSameTypeTag>) {
|
||||||
|
msg._messageView = conv_func(msg._byteStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::input_iterator IterT,
|
||||||
|
traits::adc_from_bytes_func_c<ByteStorageT, message_view_t> CONVT =
|
||||||
|
decltype(utils::AdcDefaultValueConverter<>::deserialize<message_view_t, ByteStorageT>)>
|
||||||
|
static AdcGenericNetMessage fromBytes(
|
||||||
|
IterT begin,
|
||||||
|
IterT end,
|
||||||
|
CONVT&& conv_func = utils::AdcDefaultValueConverter<>::deserialize<message_view_t, ByteStorageT>)
|
||||||
|
{
|
||||||
|
AdcGenericNetMessage msg;
|
||||||
|
msg.setBytes(begin, end);
|
||||||
|
|
||||||
|
if constexpr (!std::is_same_v<MessageViewT, traits::AdcTheSameTypeTag>) {
|
||||||
|
msg._messageView = conv_func(msg._byteStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MessageViewT _messageView;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace adc
|
||||||
Loading…
x
Reference in New Issue
Block a user