This commit is contained in:
2026-07-22 18:15:48 +03:00
parent 0130420f90
commit 4b3718f7af
3 changed files with 159 additions and 28 deletions

View File

@@ -82,6 +82,10 @@ if(SNPLIB_BUILD_EXAMPLES)
set(EXAM_LOGGER logger_example)
add_executable(${EXAM_LOGGER} examples/logger_exam.cpp)
target_link_libraries(${EXAM_LOGGER} ${PROJECT_NAME})
set(EXAM_NET net_example)
add_executable(${EXAM_NET} examples/net_exam.cpp)
target_link_libraries(${EXAM_NET} ${PROJECT_NAME})
endif()
include(GNUInstallDirs)

59
examples/net_exam.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include <list>
#include <print>
#include <snipplib/network/snplib_netproto.h>
int main()
{
snplib::snplib_netproto_stopseq_t<> proto;
std::string bytes{"SET VAL1 10\n"};
std::vector bytes_vec{std::from_range, bytes};
std::list bytes_lst{std::from_range, bytes};
std::println("BYTES VEC: {}", bytes_vec);
auto msg = proto.fromBytes(bytes_vec);
if (msg) {
std::println("MSG (from std::vector): {}", msg.value());
} else {
std::println("MSG ERR: {}", msg.error().message());
}
auto msg_l = proto.fromBytes(bytes_lst);
if (msg_l) {
std::println("MSG (from std::list): {}", msg_l.value());
} else {
std::println("MSG ERR: {}", msg_l.error().message());
}
auto vmsg = proto.fromBytes<std::vector<char>>(bytes_lst);
if (vmsg) {
std::println("VMSG (from std::list): {}", vmsg.value());
} else {
std::println("VMSG ERR: {}", vmsg.error().message());
}
std::println("\n\n");
bytes = "GET VAL2 1";
bytes_vec = {std::from_range, bytes};
bytes_lst = {std::from_range, bytes};
std::println("MSG: ", bytes_vec);
auto bs = proto.toBytes(bytes_vec);
std::println("BYTES (from std::vector): {}", bs);
auto bs1 = proto.toBytes(bytes_lst);
std::println("BYTES (from std::list): {}", bs1);
bytes_vec = proto.toBytes<decltype(bytes_vec)>(bytes_lst);
std::println("BYTES: {}", bytes_vec);
return 0;
}

View File

@@ -12,12 +12,22 @@
namespace snplib
{
/* SIMPLE STOP-SEQUENCE PROTOCOL */
/*
A valid record consists of a byte-sequence ending with given stop-sequence of bytes
e.g.:
SET ATTR 2\n\r\n
where "\n\r\n" - the stop-sequence
*/
static constexpr char SNPLIB_DEFAULT_NETPROTO_STOP_SEQ[] = "\n";
template <const char* STOP_SEQ = SNPLIB_DEFAULT_NETPROTO_STOP_SEQ>
requires(snplib_char_array_size(STOP_SEQ) > 0)
struct snplib_netproto_stopseq_t {
static constexpr std::string_view NETPROTO_STOP_SEQ{
snplib_char_array_size(STOP_SEQ) ? STOP_SEQ : SNPLIB_DEFAULT_NETPROTO_STOP_SEQ};
static constexpr std::string_view NETPROTO_STOP_SEQ{STOP_SEQ};
// returns 2-element range of the input messsage and stop-sequence
template <std::ranges::range OR, snplib_input_char_range_c IR>
@@ -50,7 +60,8 @@ struct snplib_netproto_stopseq_t {
if constexpr (std::ranges::contiguous_range<IR>) {
return std::array{std::span<const char>{message}, std::span<const char>{NETPROTO_STOP_SEQ}};
} else {
return std::array{std::ranges::subrange{message}, std::ranges::subrange{NETPROTO_STOP_SEQ}};
// return std::array{std::ranges::subrange(message), std::ranges::subrange(NETPROTO_STOP_SEQ)};
return std::make_tuple(std::ranges::subrange(message), std::ranges::subrange(NETPROTO_STOP_SEQ));
}
}
@@ -59,42 +70,99 @@ struct snplib_netproto_stopseq_t {
{
auto found = std::ranges::search(std::forward<IR>(bytes), NETPROTO_STOP_SEQ);
if (found.empty()) {
return std::unexpected(std::errc::invalid_argument);
return std::unexpected(std::make_error_code(std::errc::invalid_argument));
}
if constexpr (std::ranges::contiguous_range<IR>) {
if constexpr (std::ranges::view<OR>) {
return OR(bytes.begin(), found.begin()); // return without stop-sequence!!!
} else if constexpr (snplib_output_char_range_c<OR>) {
using inp_t = std::remove_cvref_t<IR>;
// return a view
static constexpr bool ret_view =
std::ranges::view<OR> && std::ranges::viewable_range<inp_t> &&
(std::constructible_from<OR, std::ranges::iterator_t<inp_t>, std::ranges::iterator_t<inp_t>> ||
std::constructible_from<OR, std::ranges::iterator_t<inp_t>, std::ranges::sentinel_t<inp_t>>);
if constexpr (ret_view) {
return OR(bytes.begin(), found.begin()); // return without stop-sequence!!!
} else if constexpr (snplib_output_char_range_c<OR>) {
if constexpr (!snplib_fixed_size_range_c<OR>) {
if constexpr (std::constructible_from<OR, std::ranges::iterator_t<inp_t>,
std::ranges::iterator_t<inp_t>>) {
return OR(bytes.begin(), found.begin()); // return without stop-sequence!!!
} else if constexpr (std::is_default_constructible_v<OR>) {
OR res;
std::ranges::copy(
std::forward<IR>(bytes) | std::views::take(std::distance(bytes.begin(), found.begin())),
std::back_inserter(res));
return res;
} else {
static_assert(false, "Unsupported output byte sequence type!");
}
} else {
auto Nelem = std::distance(bytes.begin(), found.begin());
if (Nelem > std::tuple_size_v<OR>) {
static_assert(false, "Invalid size of the output byte sequence type!");
}
OR res;
std::ranges::copy(
std::forward<IR>(bytes) | std::views::take(std::distance(bytes.begin(), found.begin())),
std::back_inserter(res));
auto data_it = bytes.begin();
for (auto it = res.begin(); it != res.end(); std::advance(it, 1)) {
*it = *data_it;
std::advance(data_it, 1);
}
return res;
} else {
static_assert(false, "Unsupported output byte sequence type!");
}
} else {
}
if constexpr (snplib_output_char_range_c<OR>) {
OR res;
std::ranges::copy(std::forward<IR>(bytes) | std::views::take(std::distance(bytes.begin(), found.begin())),
std::back_inserter(res)); // return without stop-sequence!!!
return res;
} else if constexpr (snplib_char_view_c<OR>) {
if constexpr (std::ranges::contiguous_range<IR>) {
return OR(bytes.begin(), found.begin()); // return without stop-sequence!!!
} else {
static_assert(false, "Unsupported output byte sequence type!");
}
} else {
static_assert(false, "Unsupported output byte sequence type!");
}
}
template <typename IR>
auto fromBytes(IR&& bytes)
requires snplib_input_char_range_c<std::remove_cvref_t<IR>>
{
using or_t = std::conditional_t<std::ranges::contiguous_range<IR>, std::span<const char>,
std::ranges::subrange<std::ranges::iterator_t<IR>>>;
return fromBytes<or_t>(std::forward<IR>(bytes));
}
};
/* BINARY BLOB PROTOCOL */
/*
* a sequence of bytes in format:
* <blob size field><bynary blob bytes>
*
blob size field: a symbolic representation of a HEXIMAL UNSIGNED INTEGER (e.g. "000000FA", MUST BE IN
UPPER-CASE!!!)
*/
template <size_t SZ_FIELD_WIDTH = 8>
requires(SZ_FIELD_WIDTH > 0 &&
SZ_FIELD_WIDTH <= 16) // not greater than allowed for 64-bit unsigned integer representation
struct snplib_netproto_binary_blob_t {
static constexpr std::array<char, 6> SZ_FIELD_FORMAT{'{', ':', '0', '0' + SZ_FIELD_WIDTH, 'X', '}'};
template <snplib_input_char_range_c IR>
auto toBytes(IR&& message)
{
static thread_local std::string Nbytes{};
Nbytes.clear();
// std::format_to(std::back_inserter(Nbytes), "{:08X}", std::ranges::size(std::forward<IR>(message)));
std::format_to(std::back_inserter(Nbytes), std::string_view(SZ_FIELD_FORMAT),
std::ranges::size(std::forward<IR>(message)));
if constexpr (std::ranges::contiguous_range<IR>) {
return std::array{std::span<const char>{Nbytes}, std::span<const char>{message}};
} else {
return std::make_tuple(std::ranges::subrange(Nbytes), std::ranges::subrange(message));
}
}
};
} // namespace snplib