start network-related part

This commit is contained in:
Timur A. Fatkhullin 2024-05-25 20:58:15 +03:00
parent 1c79026a34
commit 366d4e05b0
3 changed files with 244 additions and 12 deletions

View File

@ -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(

View File

@ -37,8 +37,8 @@ concept adc_output_char_range = std::ranges::output_range<R, CharT>;
// range of char/const char
template <typename R, typename CharT = char>
concept adc_input_char_range = std::ranges::input_range<R>;
// concept adc_input_char_range = std::ranges::input_range<CharT>;
concept adc_input_char_range =
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

230
net/adc_netmessage.h Normal file
View 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