diff --git a/common/adc_traits.h b/common/adc_traits.h index d031eef..1f39843 100644 --- a/common/adc_traits.h +++ b/common/adc_traits.h @@ -46,6 +46,10 @@ template concept adc_char_view = std::ranges::view && std::same_as, char>; +template +concept adc_view_or_output_char_range = adc_char_view || adc_output_char_range; + + template concept adc_range_of_view_char_range = std::ranges::range && std::ranges::view> && std::same_as>, char>; @@ -54,6 +58,10 @@ template concept adc_range_of_input_char_range = std::ranges::range && traits::adc_input_char_range>; + +template +concept adc_range_of_view_or_output_char_range = adc_range_of_view_char_range || adc_output_char_range; + // deduce returned type of callable // template // using adc_retval_t = std::invoke_result_t>; diff --git a/net/adc_net_concepts.h b/net/adc_net_concepts.h index f83edfa..b085713 100644 --- a/net/adc_net_concepts.h +++ b/net/adc_net_concepts.h @@ -14,7 +14,7 @@ ABSTRACT DEVICE COMPONENTS LIBRARY /* DEFINITIONS OF NETWORK COMPONENTS INTERFACES */ -namespace adc::traits +namespace adc::interfaces { @@ -92,7 +92,7 @@ template -concept adc_netservice_c = adc_input_char_range && adc_output_char_range && adc_time_duration_c && +concept adc_netservice_c = traits::adc_input_char_range && traits::adc_output_char_range && adc_time_duration_c && requires(SRVT srv, const SRVT srv_const) { typename SRVT::netservice_ident_t; @@ -103,53 +103,27 @@ concept adc_netservice_c = adc_input_char_range && adc_output_char_range< typename SRVT::endpoint_t; // asynchronous (non-blocking) operations - asyncAccept(std::declval(), + srv.asyncAccept(std::declval(), std::declval(), std::declval()); - asyncConnect(std::declval(), + srv.asyncConnect(std::declval(), std::declval(), std::declval()); - asyncSend(std::declval(), std::declval(), + srv.asyncSend(std::declval(), std::declval(), std::declval()); - asyncReceive(std::declval(), std::declval()); + srv.asyncReceive(std::declval(), std::declval()); // synchronous (blocking) operations - accept(std::declval(), std::declval()); + srv.accept(std::declval(), std::declval()); - connect(std::declval(), std::declval()); + srv.connect(std::declval(), std::declval()); - send(std::declval(), std::declval()); + srv.send(std::declval(), std::declval()); - { receive(std::declval()) } -> std::same_as; + { srv.receive(std::declval()) } -> std::same_as; - // requires requires { - // [](SRVT& srv_obj, const typename SRVT::endpoint_t& endpoint, const typename - // SRVT::async_ctx_t& ctx, - // const DURT& timeout) { - // srv_obj.asyncAccept(endpoint, ctx, timeout); - // srv_obj.asyncConnect(endpoint, ctx, timeout); - - // srv_obj.accept(endpoint, timeout); - // srv_obj.connect(endpoint, timeout); - // }(srv, typename SRVT::endpoint_t(), typename SRVT::async_ctx_t(), - // std::chrono::seconds(1)); - - // [](SRVT& srv_obj, const R& msg, const - // typename SRVT::async_ctx_t& ctx, - // const DURT& timeout) { - // srv_obj.asyncSend(msg, ctx, timeout); - // srv_obj.send(msg, timeout); - // }(srv, std::span(), typename SRVT::async_ctx_t(), - // std::chrono::seconds(1)); - - // [](SRVT& srv_obj, R& msg, const typename - // SRVT::async_ctx_t& ctx, - // const DURT& timeout) { - // srv_obj.asyncReceive(ctx, timeout); - // msg = srv_obj.receive(timeout); - // }(srv, std::string(), typename SRVT::async_ctx_t(), std::chrono::seconds(1)); - // }; + srv.shutdown(); }; @@ -171,21 +145,35 @@ concept adc_netsession_c = /* NETWORK SESSION-LEVEL PROTOCOL */ -template -concept adc_netsession_proto_c = requires(SESS_PROTOT proto, const SESS_PROTOT proto_const) { +template +concept adc_netsession_proto_c = traits::adc_input_char_range && requires(SESS_PROTOT proto, const SESS_PROTOT proto_const) { typename SESS_PROTOT::proto_ident_t; // proto_ident_t ident() const (const method) { proto_const.ident() } -> std::same_as; - [](const SESS_PROTOT& proto, IT begin, IT end) -> std::tuple { - return proto.parse(begin, end); - }; + // typename SESS_PROTOT::search_result_t; + + // search for the first occurence of valid protocol sequence in input user byte sequence + // the method must return std::tuple: + // start - input range iterator of the sequence first byte + // stop - input range iterator of the sequence end ("after-the-last" byte!!!) + // flag - true if valid sequence was found, false - otherwise + { + proto.search(std::declval()) + } -> std::same_as, std::ranges::iterator_t, bool>>; + + + // construct netsession protocol representation of input user byte sequence + // the method must return a range of char range views or output char range + { proto.toProto(std::declval()) } -> traits::adc_range_of_view_or_output_char_range; + + // return user byte sequence from input netsession protocol representation + // the method must return a view of char range or output char range + { proto.fromProto(std::declval()) } -> traits::adc_view_or_output_char_range; - // must return a view of R-range! - [](SESS_PROTOT obj, const R& r) -> std::ranges::view auto { return obj.from(r); }( - proto, std::string()); }; -} // namespace adc::traits +} // namespace adc::interfaces diff --git a/net/adc_netproto.h b/net/adc_netproto.h index aa781b7..746dcc9 100644 --- a/net/adc_netproto.h +++ b/net/adc_netproto.h @@ -27,6 +27,65 @@ static constexpr char ADC_DEFAULT_NETPROTO_STARTMARK[] = "\n\t\r\v\r\t\n"; } // namespace constants +template +struct AdcStopSeqSessionProto { + static constexpr std::string_view STOP_SEQ{STOPSEQ}; + static constexpr size_t STOP_SEQ_SIZE = STOP_SEQ.size(); + + static_assert(STOP_SEQ_SIZE, "STOP BYTE SEQUENCE MUST NOT BE AN EMPTY ONE!!!"); + + template + auto search(const R& r) + { + std::tuple, std::ranges::iterator_t, bool> res{r.begin(), r.end(), false}; + + std::get<1>(res) = std::search(r.begin(), r.end(), STOP_SEQ.begin(), STOP_SEQ.end()); + if (std::get<1>(res) != r.end()) { // move iterator to the one-past-the-end position + std::get<1>(res) = std::advance(std::get<1>(res), STOP_SEQ_SIZE); + std::get<2>(res) = true; + } + + return res; + } + + + template + auto toProto(const R& r) + { + // return 2-element array with the first element as a view of the input range and + // the second one - a view of the stop sequence + + if constexpr (std::ranges::viewable_range) { + auto res = std::array{std::ranges::subrange(r.begin(), r.end()), + std::ranges::subrange(STOP_SEQ.begin(), STOP_SEQ.end())}; + + return res; + } else { // return a copy of input range with appended stop sequence + auto res = r; + std::ranges::copy(STOP_SEQ, std::back_inserter(res)); + return res; + } + } + + template + auto fromProto(const R& r) + { + auto N = std::distance(r.begin(), r.end()); + + if (N < STOP_SEQ_SIZE) { // one must ensure for input range size correctness + return std::span>(); + } + + if constexpr (std::ranges::viewable_range) { + return std::ranges::subrange(r.begin(), r.end() - STOP_SEQ_SIZE); + } else { + R res; + std::ranges::copy(r | std::views::take(N - STOP_SEQ_SIZE), std::back_inserter(res)); + return res; + } + } +}; + template struct AdcNetProtoStopSeq : InetT { static constexpr std::string_view stopSeq{STOPSEQ};