This commit is contained in:
2026-09-29 17:58:14 +03:00
parent f7d57f3997
commit 47c6d39569
3 changed files with 48 additions and 23 deletions

View File

@@ -35,6 +35,7 @@ protected:
public: public:
using typename base_t::config_t; using typename base_t::config_t;
using result_t = std::expected<keyval_netmsg_t, typename base_t::error_t>;
keyval_netmsg_t(base_t::config_t config = {.keyval_delim = SNPLIB_DEFAULT_NETMSG_KEYVALUE_DELIM, keyval_netmsg_t(base_t::config_t config = {.keyval_delim = SNPLIB_DEFAULT_NETMSG_KEYVALUE_DELIM,
.valseq_delim = SNPLIB_DEFAULT_NETMSG_VALUEVALUE_DELIM}) .valseq_delim = SNPLIB_DEFAULT_NETMSG_VALUEVALUE_DELIM})
@@ -52,27 +53,25 @@ public:
~keyval_netmsg_t() = default; ~keyval_netmsg_t() = default;
template <char_range_c R> template <char_range_c R>
static keyval_netmsg_t fromBytes(R&& r, static result_t fromBytes(R&& r,
base_t::config_t config = {.keyval_delim = SNPLIB_DEFAULT_NETMSG_KEYVALUE_DELIM, base_t::config_t config = {.keyval_delim = SNPLIB_DEFAULT_NETMSG_KEYVALUE_DELIM,
.valseq_delim = SNPLIB_DEFAULT_NETMSG_VALUEVALUE_DELIM}) .valseq_delim = SNPLIB_DEFAULT_NETMSG_VALUEVALUE_DELIM})
{ {
keyval_netmsg_t msg; keyval_netmsg_t msg;
// deep copy // deep copy
if constexpr (std::same_as<CharRangeT, std::remove_cvref_t<R>>) { if constexpr (std::same_as<CharRangeT, std::remove_cvref_t<R>>) {
std::ranges::copy(std::forward<R>(r), std::back_inserter(msg._ownByteSeq)); std::ranges::copy(std::forward<R>(r), std::back_inserter(msg._ownByteSeq));
msg.fromCharRange(msg._ownByteSeq, std::move(config)); return msg.fromCharRange(msg._ownByteSeq, std::move(config));
} else { } else {
msg.fromCharRange(std::forward<R>(r), std::move(config)); return msg.fromCharRange(std::forward<R>(r), std::move(config));
} }
return msg;
} }
// to satisfy net_message_c-concept // to satisfy net_message_c-concept
static keyval_netmsg_t fromBytes(std::span<const char> r, static result_t fromBytes(std::span<const char> r,
base_t::config_t config = {.keyval_delim = SNPLIB_DEFAULT_NETMSG_KEYVALUE_DELIM, base_t::config_t config = {.keyval_delim = SNPLIB_DEFAULT_NETMSG_KEYVALUE_DELIM,
.valseq_delim = SNPLIB_DEFAULT_NETMSG_VALUEVALUE_DELIM}) .valseq_delim = SNPLIB_DEFAULT_NETMSG_VALUEVALUE_DELIM})
{ {
return keyval_netmsg_t::fromBytes(r, std::move(config)); return keyval_netmsg_t::fromBytes(r, std::move(config));
} }

View File

@@ -2,6 +2,7 @@
#include "../concepts/snplib_concepts.h" #include "../concepts/snplib_concepts.h"
#include "../utils/snplib_string.h" #include "../utils/snplib_string.h"
#include "snipplib/network/snplib_network.h"
/* /*
@@ -119,23 +120,36 @@ struct netproto_stopseq_t {
} }
} }
// deduces a view-type from the input range-type
template <typename IR> template <typename IR>
auto fromBytes(IR&& bytes) auto fromBytes(IR&& bytes)
requires input_char_range_c<std::remove_cvref_t<IR>> requires input_char_range_c<std::remove_cvref_t<IR>>
{ {
using or_t = std::conditional_t<std::ranges::contiguous_range<IR>, std::span<const char>, using or_t =
std::ranges::subrange<std::ranges::iterator_t<IR>>>; std::conditional_t<std::ranges::contiguous_range<IR>, std::span<const char>,
std::ranges::subrange<std::ranges::iterator_t<IR>, std::ranges::sentinel_t<IR>>>;
return fromBytes<or_t>(std::forward<IR>(bytes)); return fromBytes<or_t>(std::forward<IR>(bytes));
} }
// to satisfy 'net_proto_c' concept
template <typename CharT = char>
requires(std::same_as<CharT, char> || std::same_as<CharT, const char>)
std::expected<std::span<CharT>, std::error_code> fromBytes(std::span<CharT> bytes)
{
return fromBytes<std::span<CharT>>(bytes);
}
}; };
static_assert(net_proto_c<netproto_stopseq_t<>>, "!!!");
/* BINARY BLOB PROTOCOL */ /* BINARY BLOB PROTOCOL */
/* /*
* a sequence of bytes in format: * a sequence of bytes in format:
* <blob size field><bynary blob bytes> * <blob size field><binary blob bytes>
* *
blob size field: a symbolic representation of a HEXIMAL UNSIGNED INTEGER (e.g. "000000FA", MUST BE IN blob size field: a symbolic representation of a HEXIMAL UNSIGNED INTEGER (e.g. "000000FA", MUST BE IN
UPPER-CASE!!!) UPPER-CASE!!!)

View File

@@ -29,15 +29,23 @@ concept net_proto_c = requires(T t) {
// from session-level representation to transport-level one // from session-level representation to transport-level one
{ t.toBytes(std::declval<CharRangeT>()) } -> char_range_or_range_of_char_ranges_c; { t.toBytes(std::declval<CharRangeT>()) } -> char_range_or_range_of_char_ranges_c;
// from transport-level representation to session-level one
requires( requires(
requires { requires {
{ t.fromBytes(std::declval<std::span<const char>>()) } -> char_range_c; // { t.fromBytes(std::declval<std::span<const char>>()) } -> char_range_c;
{ t.fromBytes(std::declval<std::span<const char>>()) } -> ret_expected_c;
requires char_range_c<std::remove_cvref_t<
decltype(std::declval<T>().fromBytes(std::declval<std::span<const char>>()).value())>>;
} || } ||
requires { requires {
{ t.fromBytes(std::declval<std::span<char>>()) } -> char_range_c; // { t.fromBytes(std::declval<std::span<char>>()) } -> char_range_c;
{ t.fromBytes(std::declval<std::span<char>>()) } -> ret_expected_c;
requires char_range_c<
std::remove_cvref_t<decltype(std::declval<T>().fromBytes(std::declval<std::span<char>>()).value())>>;
}); });
}; };
template <typename T> template <typename T>
concept net_message_c = requires(const T t_const) { concept net_message_c = requires(const T t_const) {
// { t.toBytes() } -> char_range_or_range_of_char_ranges_c; // { t.toBytes() } -> char_range_or_range_of_char_ranges_c;
@@ -46,10 +54,12 @@ concept net_message_c = requires(const T t_const) {
// can be constructed from contiguous byte range // can be constructed from contiguous byte range
requires( requires(
requires { requires {
{ T::fromBytes(std::declval<std::span<const char>>()) } -> std::same_as<T>; // { T::fromBytes(std::declval<std::span<const char>>()) } -> std::same_as<T>;
{ T::fromBytes(std::declval<std::span<const char>>()) } -> ret_expected_type_c<T>;
} || } ||
requires { requires {
{ T::fromBytes(std::declval<std::span<char>>()) } -> std::same_as<T>; // { T::fromBytes(std::declval<std::span<char>>()) } -> std::same_as<T>;
{ T::fromBytes(std::declval<std::span<char>>()) } -> ret_expected_type_c<T>;
}); });
}; };
@@ -101,9 +111,9 @@ concept net_listener_c = requires(T t, const T t_const) {
{ t.accept() } -> async_retval_c<typename T::connection_t>; { t.accept() } -> async_retval_c<typename T::connection_t>;
{ t.startListen() } -> ret_error_c; { t.startListening() } -> ret_error_c;
t.stopListen(); t.stopListening();
{ t_const.endpoint() } -> net_endpoint_c; { t_const.endpoint() } -> net_endpoint_c;
}; };
@@ -116,7 +126,7 @@ concept net_initiator_role_c = requires {
[]() { []() {
[[maybe_unused]] static constexpr std::array arr{// server role (listener of connections) [[maybe_unused]] static constexpr std::array arr{// server role (listener of connections)
T::ROLE_SERVER, T::ROLE_SERVER,
// cleant role (opener of connections) // client role (opener of connections)
T::ROLE_CLIENT}; T::ROLE_CLIENT};
}(); }();
}; };
@@ -128,8 +138,10 @@ enum class net_initiator_role_e : int { ROLE_SERVER, ROLE_CLIENT };
template <typename T> template <typename T>
concept net_initiator_c = concept net_initiator_c =
requires(T t, const T t_const) { requires(T t, const T t_const) {
// common part // common part:
// must contain a static compile-time constant 'ROLE' of type satisfied to 'net_initiator_role_c' concept
requires net_initiator_role_c<decltype(T::ROLE)>; requires net_initiator_role_c<decltype(T::ROLE)>;
// to be sure 'ROLE' is compile-time constant
[]() { [[maybe_unused]] static constexpr auto val = T::ROLE; }(); []() { [[maybe_unused]] static constexpr auto val = T::ROLE; }();
net_connection_c<typename T::connection_t>; net_connection_c<typename T::connection_t>;
@@ -139,9 +151,9 @@ concept net_initiator_c =
// server-role // server-role
{ t.accept() } -> async_retval_c<typename T::connection_t>; { t.accept() } -> async_retval_c<typename T::connection_t>;
{ t.startListen() } -> ret_error_c; { t.startListening() } -> ret_error_c;
t.stopListen(); t.stopListening();
}) && ((T::ROLE != decltype(T::ROLE)::ROLE_CLIENT) || requires(T t) { // use of short-circuiting logic!!! }) && ((T::ROLE != decltype(T::ROLE)::ROLE_CLIENT) || requires(T t) { // use of short-circuiting logic!!!
// client-role // client-role
{ t.open() } -> async_retval_c<typename T::connection_t>; { t.open() } -> async_retval_c<typename T::connection_t>;