#pragma once #include "../common/adc_utils.h" // #include "adc_netmsg.h" namespace adc { /* ABSTRACT DEVICE DEFAULT APPLICATION-LEVEL NETWORK PROTOCOL DEFINITIONS */ namespace constants { static constexpr char ADC_DEFAULT_KEY_VALUE_DELIMITER1[] = " "; static constexpr char ADC_DEFAULT_KEY_PARAM_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_PARAM_PARAM_DELIMITER[] = " "; static constexpr char ADC_DEFAULT_COMPOSITE_PARAM_DELIMITER[] = ","; } // namespace constants template class AdcKeyValueMessage1 { public: static constexpr std::span keyValueDelimiter{KEY_VALUE_DELIM, sizeof(KEY_VALUE_DELIM) - 1}; static constexpr std::span valueDelimiter{VALUE_DELIM, sizeof(VALUE_DELIM) - 1}; AdcKeyValueMessage1(ByteSeqT& byte_seq) : _byteSequence(byte_seq) {} virtual ~AdcKeyValueMessage1() = default; template requires(traits::adc_char_view && std::ranges::contiguous_range) || traits::adc_output_char_range auto key() const { if constexpr (traits::adc_char_view && std::ranges::contiguous_range) { auto bs = utils::AdcTrimSpacesView(_byteSequence, utils::AdcTrimType::TRIM_LEFT); auto found = std::ranges::search(bs, keyValueDelimiter); // if (found.empty) { // no value // return bs; // } return utils::AdcTrimSpacesView(std::span(bs.begin(), found.begin()), utils::AdcTrimType::TRIM_RIGHT); } else { T res; auto bs = _byteSequence | std::views::drop_while([](const auto& ch) { return ch = ' '; }); auto found = std::ranges::search(bs, keyValueDelimiter); std::ranges::copy(bs.begin(), found.begin(), std::back_inserter(res)); // if (found.empty()) { // no value // std::ranges::copy(bs, std::back_inserter(res)); // } else { // std::ranges::copy(bs.begin(), found.begin(), std::back_inserter(res)); // } return res; } } auto key() const { if constexpr (std::ranges::contiguous_range) { return key(); } else { return key(); } } template requires(traits::adc_char_view && std::ranges::contiguous_range) || traits::adc_output_char_range auto value() const { if constexpr (traits::adc_char_view && std::ranges::contiguous_range) { auto bs = utils::AdcTrimSpacesView(_byteSequence, utils::AdcTrimType::TRIM_LEFT); auto found = std::ranges::search(bs, keyValueDelimiter); // if (found.empty()) { // no value // return T(); // } return T(found.end(), _byteSequence.end()); } else { T res; auto bs = _byteSequence | std::views::drop_while([](const auto& ch) { return ch = ' '; }); auto found = std::ranges::search(bs, keyValueDelimiter); if (!found.empty()) { std::ranges::copy(found.end(), _byteSequence.end(), std::back_inserter(res)); } return res; } } auto value() const { if constexpr (std::ranges::contiguous_range) { return value(); } else { return value(); } } template requires traits::adc_output_char_range AdcKeyValueMessage1& setKeyValue(KeyT&& key, ValueT&& value) { if (std::ranges::size(_byteSequence)) { _byteSequence = _byteSequence(); } std::ranges::copy( utils::AdcDefaultValueConverter::template serialize(std::forward(key)), std::back_inserter(_byteSequence)); std::ranges::copy(keyValueDelimiter, std::back_inserter(_byteSequence)); std::ranges::copy( utils::AdcDefaultValueConverter::template serialize(std::forward(value)), std::back_inserter(_byteSequence)); return *this; } template AdcKeyValueMessage1& setValue(ValueT&& value) { std::vector kw; std::ranges::copy(key>(), std::back_inserter(kw)); return setKeyValue(kw, std::forward(value)); } protected: ByteSeqT& _byteSequence; }; template class AdcDeviceNetMessage : public AdcKeyValueMessage1 { using base_t = AdcKeyValueMessage1; public: static constexpr std::span keyParamDelimiter{KEY_PARAM_DELIM, sizeof(KEY_PARAM_DELIM) - 1}; static constexpr std::span paramParamDelimiter{PARAM_PARAM_DELIM, sizeof(PARAM_PARAM_DELIM) - 1}; static constexpr std::span compParamDelimiter{COMPOSITE_PARAM_DELIM, sizeof(COMPOSITE_PARAM_DELIM) - 1}; AdcDeviceNetMessage(ByteSeqT& byte_seq) : base_t(byte_seq) {} template VT keyword() const { // auto v = utils::AdcTrimSpaces(base_t::template key()); // return VT(std::begin(v), std::end(v)); std::span key; // first, remove spaces at the beginning and end of byte sequence auto bs = utils::AdcTrimSpacesView>(this->_byteSequence); auto found = std::ranges::search(bs, keyParamDelimiter); if (found.empty()) { // only keyword return VT(bs.begin(), bs.end()); } key = std::span(bs.begin(), found.begin()); return utils::AdcTrimSpacesView(key); } auto keyword() const { return keyword(); } template auto params(size_t start = 0, size_t N = std::numeric_limits::max()) { auto val = base_t::template value>(); // auto p = utils::AdcTokenManip(val).tokens(start, N); R res; std::ranges::for_each(std::views::split(val, keyParamDelimiter) | std::views::drop(start) | std::views::take(N), [&res](const auto& el) { // remove spaces std::back_inserter(res) = utils::AdcTrimSpacesView>(el); // std::ranges::copy(utils::AdcTrimSpaces(el), std::back_inserter(res)); }); return res; } auto params(size_t start = 0, size_t N = std::numeric_limits::max()) { return params>(start, N); } template auto joinParams(size_t start = 0, size_t N = std::numeric_limits::max()) { R res; utils::AdcJoinRange(params>>(start, N), paramParamDelimiter, res); return res; } }; } // namespace adc