#pragma once #include #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 concept adc_to_bytes_func_c = std::invocable && !std::convertible_to, BT>; // from bytes to message view converter concept template concept adc_from_bytes_func_c = std::invocable && std::convertible_to, VT>; template concept adc_netmsg_converter_c = requires(T t) { { t.template serialize(std::declval()) } -> std::same_as; { t.template deserialize(std::declval()) } -> std::same_as; }; struct AdcTheSameTypeTag { }; } // namespace traits namespace utils { template OutR, traits::adc_input_char_range InR, traits::adc_input_char_range DelimT = std::string_view> size_t adcSplitRangeToTokens(OutR& result, const InR& input, const DelimT& delim = std::string_view(" ")) { decltype(std::ranges::split_view(input, delim)) vv; if constexpr (std::is_array_v) { vv = input | std::views::split(std::string_view(delim)); } else { vv = input | std::views::split(delim); } std::ranges::copy(vv, std::back_inserter(result)); return std::ranges::distance(vv.begin(), vv.end()); } } // namespace utils template ByteStorageT, std::ranges::output_range> StorageSeqT> class AdcNetMessageInterface { protected: ByteStorageT _byteStorage; StorageSeqT _storageSequence; AdcNetMessageInterface() : _byteStorage(), _storageSequence({_byteStorage}){}; template 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; virtual void updateState() = 0; public: typedef ByteStorageT byte_storage_t; typedef StorageSeqT storage_seq_t; bool messageEmpty() const { return byteSize() == 0; } bool byteStorageEmpty() const { size_t sz = std::ranges::distance(_byteStorage.begin(), _byteStorage.end()); return sz == 0; } template void appendBytes(const T& v, const Ts&... vs) { if constexpr (std::is_array_v>) { appendBytes(std::string_view(v), vs...); } else { if constexpr (traits::adc_input_char_range) { std::ranges::copy(v, std::back_inserter(_byteStorage)); } else if constexpr (traits::formattable) { std::format_to(std::back_inserter(_byteStorage), v); } else { static_assert(false, "UNSUPPORTED TYPE!!!"); } updateState(); } if constexpr (sizeof...(Ts)) { appendBytes(vs...); } } template void setBytes(const T& v, const Ts&... vs) { _byteStorage = ByteStorageT(); appendBytes(v, vs...); } // template // void appendBytes(const T& v, const Ts&... vs) // { // if constexpr (std::is_array_v>) { // appendBytes(std::string_view(v), vs...); // } else { // std::ranges::copy(v, std::back_inserter(_byteStorage)); // } // if constexpr (sizeof...(Ts)) { // appendBytes(vs...); // } // } // template // void appendBytes(const T& v, const Ts&... vs) // { // std::format_to(std::back_inserter(_byteStorage), v); // if constexpr (sizeof...(Ts)) { // appendBytes(vs...); // } // } template void appendBytes(IterT begin, IterT end) { std::copy(begin, end, std::back_inserter(_byteStorage)); updateState(); } // template // void setBytes(const T& v, const Ts&... vs) // { // _byteStorage = ByteStorageT(); // appendBytes(v, vs...); // updateState(); // } // template // void setBytes(const T& v, const Ts&... vs) // { // _byteStorage = ByteStorageT(); // appendBytes(v, vs...); // updateState(); // } template void setBytes(IterT begin, IterT end) { _byteStorage = ByteStorageT(begin, end); appendBytes(begin, end); updateState(); } 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; }; /* GENERIC (NOTHING SPECIAL) NETWORK MESSAGE */ template ByteStorageT = std::vector> class AdcGenericNetMessage : public AdcNetMessageInterface, 1>> { using base_t = AdcNetMessageInterface, 1>>; public: using typename base_t::byte_storage_t; using typename base_t::storage_seq_t; // using base_t::appendBytes; // using base_t::setBytes; using base_t::base_t; virtual ~AdcGenericNetMessage() = default; const storage_seq_t& storageSeq() override { this->_storageSequence[0] = this->_byteStorage; return this->_storageSequence; }; protected: void updateState() override {} }; namespace constants { static constexpr char ADC_DEFAULT_TOKEN_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_KEY_PARAM_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " "; } // namespace constants template ByteStorageT = std::vector> class AdcTokenNetMessage : public AdcGenericNetMessage { using base_t = AdcGenericNetMessage; public: static constexpr std::string_view tokenDelimiter{TOKEN_DELIM}; using typename base_t::byte_storage_t; using typename base_t::storage_seq_t; using base_t::base_t; virtual ~AdcTokenNetMessage() = default; template void appendTokens(const R& r) { using el_t = std::ranges::range_value_t; static_assert(traits::adc_input_char_range || traits::formattable, "INVALID TYPE OF INPUT TOKENS!!!"); size_t n_toks = 0; if ((n_toks = std::ranges::distance(r.begin(), r.end())) == 0) { return; } if (!this->byteStorageEmpty()) { this->appendBytes(tokenDelimiter); } auto v_start = r | std::views::take(n_toks - 1); for (const auto& el : v_start) { this->appendBytes(el); this->appendBytes(tokenDelimiter); } this->appendBytes(*(r.end()--)); // last element } template void setTokens(const R& r) { this->_byteStorage = ByteStorageT(); appendTokens(r); } template R> void tokens(R& r) { if (this->byteStorageEmpty()) { return; } std::ranges::copy(this->_byteStorage | std::views::split(AdcTokenNetMessage::tokenDelimiter), std::back_inserter(r)); } protected: // std::vector _tokens; void updateState() override {} }; template ByteStorageT = std::vector> class AdcKeyParamNetMessage : public AdcGenericNetMessage { using base_t = AdcGenericNetMessage; public: static constexpr std::string_view keyparamDelimiter{KEY_PARAM_DELIM}; static constexpr std::string_view paramparamDelimiter{PARAM_PARAM_DELIM}; using typename base_t::byte_storage_t; using typename base_t::storage_seq_t; using base_t::base_t; virtual ~AdcKeyParamNetMessage() = default; // key and params template void setKeyParam(KeyT&& key, ParamTs&&... params) { this->_byteStorage = ByteStorageT(); if constexpr (sizeof...(ParamTs)) { this->setBytes(std::forward(key), keyparamDelimiter); setKeyParamHelper(std::forward(params)...); } else { this->setBytes(std::forward(key)); } } template R key() const { R val; if (this->byteStorageEmpty()) { return val; } auto v = this->_byteStorage | std::views::split(keyparamDelimiter); std::ranges::copy(v | std::views::take(1), std::back_inserter(val)); return val; } template R> R params(size_t start = 0, size_t N = std::numeric_limits::max()) const { R pars; if (this->byteStorageEmpty() || !N) { return pars; } auto v = this->_byteStorage | std::views::split(keyparamDelimiter); size_t k, num = N, n_pars = std::ranges::distance(v.begin(), v.end()) - 1; if (!n_pars) { return; } n_pars = 0; for (auto& p : v | std::views::drop(1)) { auto pv = p | std::views::split(paramparamDelimiter); n_pars += std::ranges::distance(pv.begin(), pv.end()); if (n_pars < start) { k = start - n_pars; continue; } else { k = 0; } std::ranges::copy(pv | std::views::drop(k) | std::views::take(num), std::back_inserter(pars)); num -= std::ranges::distance(pars.begin(), pars.end()); if (!num) { break; } } return pars; } template R paramsBytes(size_t start = 0, size_t N = std::numeric_limits::max()) const { R pars_bytes; if (this->byteStorageEmpty() || !N) { return pars_bytes; } auto p = params>(start, N); if (std::ranges::distance(p.begin(), p.end())) { } return pars_bytes; } protected: template void setKeyParamHelper(ParamT&& param, ParamTs&&... params) { this->appendBytes(std::forward(param)); if constexpr (sizeof...(ParamTs)) { this->appendBytes(paramparamDelimiter); setKeyParamHelper(std::forward(params)...); } } }; } // namespace adc