diff --git a/CMakeLists.txt b/CMakeLists.txt index cdd9a37..beaa3ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,6 +259,9 @@ if(BUILD_TESTS) add_executable(mcc_pzone_test tests/mcc_pzone_test.cpp) target_link_libraries(mcc_pzone_test PRIVATE ${PROJECT_NAME}) + + add_executable(mcc_netmsg_test tests/mcc_netmsg_test.cpp) + target_link_libraries(mcc_netmsg_test PRIVATE ${PROJECT_NAME}) else() # This is just a stub to allow access to the path and library settings for the ${PROJECT_NAME} target during development add_executable(just_stub EXCLUDE_FROM_ALL main.cpp) diff --git a/mcc_constants.h b/mcc_constants.h index 83ac488..5a46114 100644 --- a/mcc_constants.h +++ b/mcc_constants.h @@ -27,6 +27,7 @@ static constexpr double MCC_TWO_PI = std::numbers::pi * 2.0; static constexpr double MCC_SIDERAL_TO_UT1_RATIO = 1.002737909350795; // sideral/UT1 static constexpr double MCC_J2000_MJD = 51544.5; +static constexpr double MCC_MJD_ZERO = 2400000.5; // a value to represent of infinite time duration according to type of duration representation diff --git a/mcc_deserializer.h b/mcc_deserializer.h index 4f66e40..ea1fa28 100644 --- a/mcc_deserializer.h +++ b/mcc_deserializer.h @@ -197,7 +197,7 @@ struct MccDeserializer : MccDeserializerBase { static_assert(std::ranges::output_range, "INVALID RANGE TYPE!!!"); // no reference or constants allowed - static_assert(std::is_reference_v || std::is_const_v, "INVALID RANGE ELEMENT TYPE!!!"); + static_assert(!(std::is_reference_v || std::is_const_v), "INVALID RANGE ELEMENT TYPE!!!"); MccDeserializer dsr; return deserializingRange(dsr, input, value, params); @@ -206,7 +206,7 @@ struct MccDeserializer : MccDeserializerBase { MccDeserializer dsr; - auto err = dsr(trimSpaces(input), vd, params); + auto err = dsr(utils::trimSpaces(input), vd, params); if (err) { return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER); } @@ -370,4 +370,59 @@ struct MccDeserializer : MccDeserializerBase { }; +template <> +struct MccDeserializer : MccDeserializerBase { + static constexpr std::string_view deserializerName{"MCC-ANGLE-FORMAT-PREC-DESERIALIZER"}; + + template + error_t operator()(traits::mcc_input_char_range auto const& input, + MccSerializedAngleFormatPrec& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + // valid format: hour_prec[deg_precdecimals] + + std::vector v; + + auto err = MccDeserializer{}(input, v); + if (err) { + return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER; + } + + if (v.size() > 0) { + value.hour_prec = v[0]; + } + + if (v.size() > 1) { + value.deg_prec = v[1]; + } + + if (v.size() > 2) { + value.decimals = v[2]; + } + + return MccDeserializerErrorCode::ERROR_OK; + } +}; + + + +template <> +struct MccDeserializer : MccDeserializerBase { + static constexpr std::string_view deserializerName{"MCC-COORD-PAIR-FORMAT-DESERIALIZER"}; + + template + error_t operator()(traits::mcc_input_char_range auto const& input, + MccSerializedCoordPairFormat& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + value = MccSerializedCoordPairFormatStrToValue(input); + + if (value != MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_UNKNOWN){ + return MccDeserializerErrorCode::ERROR_OK; + } else { + return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE; + } + } +}; + } // namespace mcc::impl diff --git a/mcc_netserver_proto.h b/mcc_netserver_proto.h index 03f092c..12dfe1d 100644 --- a/mcc_netserver_proto.h +++ b/mcc_netserver_proto.h @@ -8,10 +8,11 @@ #include #include -#include "mcc_angle.h" -#include "mcc_defaults.h" -#include "mcc_generics.h" + + #include "mcc_utils.h" +#include "mcc_serializer.h" +#include "mcc_deserializer.h" namespace mcc::network { @@ -60,57 +61,6 @@ static constexpr std::string_view MCC_COMMPROTO_KEYWORD_RESTART_SERVER_STR = "RE /* BELOW IS ONE OF THE PROTOCOL OPTIONS CORRESPONDING MCC_GENERIC_MOUNT_C CONCEPT */ -/* predefined parameters */ - -static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_RADEC_ICRS = "RADEC_ICRS"; // ICRS RA and DEC -static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_RADEC = "RADEC"; // apparent RA and DEC -static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_HADEC = "HADEC"; // apparent HA and DEC -static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_AZZD = "AZZD"; // azimuth and zenithal distance -static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_AZALT = "AZALT"; // azimuth and altitude -static constexpr std::string_view MCC_COMMPROTO_COORD_KIND_XY = "XY"; // hardware (encoder) coordinates - - -// static constexpr MccCoordPairKind mcc_str2pairkind(std::string_view spair) -// { -// return spair == MCC_COMMPROTO_COORD_KIND_RADEC_ICRS ? MccCoordPairKind::COORDS_KIND_RADEC_ICRS -// : spair == MCC_COMMPROTO_COORD_KIND_RADEC ? MccCoordPairKind::COORDS_KIND_RADEC_APP -// : spair == MCC_COMMPROTO_COORD_KIND_HADEC ? MccCoordPairKind::COORDS_KIND_HADEC_APP -// : spair == MCC_COMMPROTO_COORD_KIND_AZZD ? MccCoordPairKind::COORDS_KIND_AZZD -// : spair == MCC_COMMPROTO_COORD_KIND_AZALT ? MccCoordPairKind::COORDS_KIND_AZALT -// : spair == MCC_COMMPROTO_COORD_KIND_XY ? MccCoordPairKind::COORDS_KIND_XY -// : MccCoordPairKind::COORDS_KIND_GENERIC; -// } - -template -static constexpr MccCoordPairKind mcc_str2pairkind(R&& spair) -{ - if constexpr (std::is_pointer_v>) { - return mcc_str2pairkind(std::string_view{spair}); - } - - const auto hash = mcc::utils::FNV1aHash(std::forward(spair)); - - return hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_RADEC_ICRS) ? MccCoordPairKind::COORDS_KIND_RADEC_ICRS - : hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_RADEC) ? MccCoordPairKind::COORDS_KIND_RADEC_APP - : hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_HADEC) ? MccCoordPairKind::COORDS_KIND_HADEC_APP - : hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_AZZD) ? MccCoordPairKind::COORDS_KIND_AZZD - : hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_AZALT) ? MccCoordPairKind::COORDS_KIND_AZALT - : hash == mcc::utils::FNV1aHash(MCC_COMMPROTO_COORD_KIND_XY) ? MccCoordPairKind::COORDS_KIND_XY - : MccCoordPairKind::COORDS_KIND_GENERIC; -} - - -static constexpr std::string_view mcc_pairkind2str(MccCoordPairKind kind) -{ - return kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS ? MCC_COMMPROTO_COORD_KIND_RADEC_ICRS - : kind == MccCoordPairKind::COORDS_KIND_RADEC_APP ? MCC_COMMPROTO_COORD_KIND_RADEC - : kind == MccCoordPairKind::COORDS_KIND_HADEC_APP ? MCC_COMMPROTO_COORD_KIND_HADEC - : kind == MccCoordPairKind::COORDS_KIND_AZZD ? MCC_COMMPROTO_COORD_KIND_AZZD - : kind == MccCoordPairKind::COORDS_KIND_AZALT ? MCC_COMMPROTO_COORD_KIND_AZALT - : kind == MccCoordPairKind::COORDS_KIND_XY ? MCC_COMMPROTO_COORD_KIND_XY - : "UNKNOWN"; -} - /* keywords */ @@ -301,149 +251,14 @@ template specializations + struct DefaultSerializer { - protected: - using base_t = mcc::utils::MccSimpleDeserializer; - - inline static mcc::MccCelestialPointDeserializer _cpDeserializer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}; - inline static mcc::MccEqtHrzCoordsDeserializer _eqhrDeserializer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}; - inline static mcc::MccTelemetryDataDeserializer _telemetryDeserializer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}; - - public: - DefaultDeserializer() : base_t(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ) {} - - template - std::error_code operator()(IR&& bytes, VT& value) const + template + auto operator()(OR& bytes, const T& value, mcc_serialization_params_c auto const& pars) const { - if constexpr (mcc_telemetry_data_c) { - return _telemetryDeserializer(std::forward(bytes), value); - } else if constexpr (mcc_eqt_hrz_coord_c) { - return _eqhrDeserializer(std::forward(bytes), value); - } else if constexpr (mcc_celestial_point_c) { - return _cpDeserializer(std::forward(bytes), value); - } else if constexpr (std::same_as) { - value = MccCoordStrToPairKind(bytes); - if (value == MccCoordPairKind::COORDS_KIND_UNKNOWN) { - // return std::make_error_code(std::errc::invalid_argument); - return MccCoordinateConvErrorCode::ERROR_INVALID_CPAIR; - } - } else if constexpr (std::same_as) { - std::string v; - auto ec = (*this)(std::forward(bytes), v); - if (ec) { - return ec; - } - - if (v.compare(MCC_COMMPROTO_KEYWORD_COORDFMT_SEXGM_STR) == 0) { - value = MccCoordinateSerializer::SerializedCoordFormat::CFMT_SGM; - } else if (v.compare(MCC_COMMPROTO_KEYWORD_COORDFMT_FIXED_STR) == 0) { - value = MccCoordinateSerializer::SerializedCoordFormat::CFMT_DEGREES; - } else { - // return std::make_error_code(std::errc::invalid_argument); - return MccCoordinateConvErrorCode::ERROR_INVALID_COORD_FMT; - } - } else if constexpr (std::same_as) { - std::vector v; - auto ec = (*this)(std::forward(bytes), v); - if (ec) { - // return ec; - return MccCoordinateConvErrorCode::ERROR_INVALID_COORD_PREC; - } - - auto hprec = v[0]; - value.hour_prec = hprec > 0 ? (hprec < std::numeric_limits::max() - ? hprec - : std::numeric_limits::max()) - : 2; - if (v.size() == 1) { - value.deg_prec = 1; - } else { - auto dprec = v[1]; - value.deg_prec = dprec > 0 ? dprec < std::numeric_limits::max() - ? dprec - : std::numeric_limits::max() - : 1; - } - } else { - return base_t::operator()(std::forward(bytes), value); - } - - return {}; - } - }; - - - class DefaultSerializer - { - friend class MccNetMessage; - - MccCoordinateSerializer::SerializedCoordFormat _coordFmt{}; - MccCoordinateSerializer::SexagesimalCoordPrec _coordPrec{}; - - public: - template - void operator()(const T& value, OR& bytes) - { - if constexpr (std::is_arithmetic_v) { - std::format_to(std::back_inserter(bytes), "{}", value); - } else if constexpr (std::convertible_to) { - std::ranges::copy(static_cast(value), std::back_inserter(bytes)); - } else if constexpr (std::constructible_from) { - std::ranges::copy(std::string(value), std::back_inserter(bytes)); - } else if constexpr (traits::mcc_char_range) { - std::ranges::copy(std::string(value.begin(), value.end()), std::back_inserter(bytes)); - // } else if constexpr (std::same_as) { - // std::ranges::copy(mcc_pairkind2str(value), std::back_inserter(bytes)); - } else if constexpr (traits::mcc_time_duration_c) { - (*this)(value.count(), bytes); - } else if constexpr (mcc_telemetry_data_c) { - static MccTelemetryDataSerializer sr; - - sr.setDelimiter(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - sr.setFormat(_coordFmt); - sr.setPrecision(_coordPrec); - - sr(value, bytes); - } else if constexpr (mcc_eqt_hrz_coord_c) { - static MccEqtHrzCoordsSerializer sr; - - sr.setDelimiter(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - sr.setFormat(_coordFmt); - sr.setPrecision(_coordPrec); - - sr(value, bytes); - } else if constexpr (mcc_celestial_point_c) { - static MccCelestialPointSerializer sr; - - sr.setDelimiter(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ); - sr.setFormat(_coordFmt); - sr.setPrecision(_coordPrec); - - sr(value, bytes); - } else if constexpr (std::ranges::range) { - auto sz = std::ranges::size(value); - if (sz == 0) { - return; - } - - (*this)(*value.begin(), bytes); // the first element - - if (sz > 1) { - for (auto const& el : value | std::views::drop(1)) { - std::ranges::copy(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, std::back_inserter(bytes)); - (*this)(el, bytes); - } - } - } else if constexpr (std::same_as) { - std::format_to(std::back_inserter(bytes), "{}{}{}{}{}", value.value(), - MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, value.message(), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, - value.category().name()); - } else if constexpr (std::formattable) { - std::format_to(std::back_inserter(bytes), "{}", value); - } else { - static_assert(false, "UNSUPPORTED TYPE!!!"); - } + return impl::MccSerializer{}(bytes, value, pars); } }; @@ -588,13 +403,15 @@ public: template std::expected paramValue(size_t idx, DeserFuncT&& deser_func) const { + static_assert(std::invocable, "INVALID DESERIALIZTION FUNCTION!"); + if (idx >= _params.size()) { return std::unexpected{std::make_error_code(std::errc::value_too_large)}; } T val; - auto ec = std::forward(deser_func)(_params[idx], val); + auto ec = std::forward(deser_func)(_params[idx], val, _serializationParams); if (ec) { return std::unexpected(ec); } else { @@ -605,7 +422,7 @@ public: template std::expected paramValue(size_t idx) const { - return paramValue(idx, _defaultDeserializer); + return paramValue(idx, impl::MccDeserializer{}); // use one of specialization of MccDeserializer templated class } @@ -637,7 +454,7 @@ public: // // serializing function SerFuncT - a callable with the signature: // template - // void ser_func(const T& val, R&& buffer) + // void ser_func(R&& buffer, const T& val, mcc_serialization_params_t const& pars) // template std::error_code construct(SerFuncT&& ser_func, KT&& key, PTs&&... params) @@ -743,69 +560,30 @@ protected: BYTEREPR_T _msgBuffer{}; - inline static DefaultDeserializer _defaultDeserializer{}; - DefaultSerializer _defaultSerializer{}; - template - void convertFunc(std::vector& idx, const T& par, const Ts&... pars) - { - if constexpr (std::same_as) { - _defaultSerializer._coordFmt = par; - if constexpr (sizeof...(Ts)) { - convertFunc(idx, pars...); - } - } else if constexpr (std::same_as) { - _defaultSerializer._coordPrec = par; - if constexpr (sizeof...(Ts)) { - convertFunc(idx, pars...); - } - } else { - convertFunc(_defaultSerializer, idx, par, pars...); - // idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); - - // _defaultSerializer(par, _msgBuffer); - - // idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); - - // if constexpr (sizeof...(Ts)) { - // std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); - - // convertFunc(idx, pars...); - // } - } - }; + impl::mcc_serialization_params_t _serializationParams{.seq_delim{MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ}, .elem_delim{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ}}; template void convertFunc(SerFuncT&& ser_func, std::vector& idx, const T& par, const Ts&... pars) requires(!std::same_as, std::vector>) { - if constexpr (std::derived_from, DefaultSerializer>) { - if constexpr (std::same_as) { - // _defaultSerializer._coordFmt = par; - ser_func._coordFmt = par; - } else if constexpr (std::same_as) { - _defaultSerializer._coordPrec = par; - } else { - idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); - std::forward(ser_func)(par, _msgBuffer); - - idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); - - if constexpr (sizeof...(Ts)) { - std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); - } - } + if constexpr (std::same_as) { + _serializationParams.coordpair_format = par; + } else if constexpr (std::same_as) { + _serializationParams.angle_prec = par; } else { idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); - std::forward(ser_func)(par, _msgBuffer); + // convertFunc(std::forward(ser_func), idx, par); + + std::forward(ser_func)(_msgBuffer, par, _serializationParams); idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end())); if constexpr (sizeof...(Ts)) { - std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer)); + std::ranges::copy(_serializationParams.seq_delim, std::back_inserter(_msgBuffer)); } } diff --git a/mcc_serializer.h b/mcc_serializer.h index f62e162..021d13f 100644 --- a/mcc_serializer.h +++ b/mcc_serializer.h @@ -143,7 +143,8 @@ protected: return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); } if (++i < N) { - MccSerializerBase::addSeqDelimiter(output, params); + // MccSerializerBase::addSeqDelimiter(output, params); + MccSerializerBase::addElemDelimiter(output, params); } } @@ -163,31 +164,26 @@ struct MccSerializer : MccSerializerBase { VT const& value, ParamsT const& params = mcc_serialization_params_t{}) { - if constexpr (std::formattable) { - std::format_to(std::back_inserter(output), "{}", value); - } else if constexpr (std::convertible_to) { - auto err = MccSerializer{}(output, static_cast(value), params); - if (err) { - return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); - } + if constexpr (std::convertible_to) { + std::string s = value; + std::ranges::copy(s, std::back_inserter(output)); + // auto err = MccSerializer{}(output, static_cast(value), params); + // if (err) { + // return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); + // } } else if constexpr (std::ranges::range) { using value_t = std::remove_cv_t>; // special range (character sequence) if constexpr (std::same_as) { - std::string str; - std::ranges::copy(value, std::back_inserter(str)); - - auto err = MccSerializer{}(output, str, params); - if (err) { - return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER); - } - + std::ranges::copy(value, std::back_inserter(output)); } else { MccSerializer sr; return MccSerializerBase::serializeRange(sr, value, output, params); } + } else if constexpr (std::formattable) { + std::format_to(std::back_inserter(output), "{}", value); } else { static_assert(false, "UNSUPPORTED TYPE!!!"); } @@ -199,10 +195,29 @@ struct MccSerializer : MccSerializerBase { /* SPECIALIZATION FOR THE SOME CONCEPTS */ + +template +struct MccSerializer : MccSerializerBase { + virtual ~MccSerializer() = default; + + constexpr static std::string_view serializerName{"MCC-TIME-DURATION-SERIALIZER"}; + + template + error_t operator()(traits::mcc_output_char_range auto& output, + VT const& value, + ParamsT const& params = mcc_serialization_params_t{}) + { + std::format_to(std::back_inserter(output), "{}", value.count()); + + return MccSerializerErrorCode::ERROR_OK; + } +}; + + + /* std::chrono::sys_time variants and its sequence */ -template - requires traits::mcc_systime_c +template struct MccSerializer : MccSerializerBase { virtual ~MccSerializer() = default; diff --git a/tests/mcc_netmsg_test.cpp b/tests/mcc_netmsg_test.cpp new file mode 100644 index 0000000..f06a691 --- /dev/null +++ b/tests/mcc_netmsg_test.cpp @@ -0,0 +1,73 @@ +#include +#include + +#include + +int main() +{ + using msg1_t = mcc::network::MccNetMessage; + using msg2_t = mcc::network::MccNetMessage; + + mcc::network::MccNetMessage msg3("ACK"); + + std::string_view sv{"TARGET 11:22:33.212; -0.23876984; RADEC "}; + std::vector arr{sv.begin(), sv.end()}; + + msg1_t msg1; + + msg1.fromCharRange(arr); + + std::println("msg.key = <{}>", msg1.keyword()); + std::println("msg.par[1] = <{}>", msg1.param(1)); + + std::vector vd{1.1, 2.2, 3.3}; + msg2_t msg2("ACK", 12.43298042, "EEE", std::chrono::seconds(10), vd); + // msg2_t msg2("ACK"); + + std::println("msg.bytes = <{}>",msg2.byteRepr()); + std::println("msg.key = <{}>", msg2.keyword()); + std::println("msg.par[1] = <{}>", msg2.param(1)); + std::println("msg.par[2] = <{}>", msg2.param(2)); + + + auto p2 = msg2.paramValue(2); + std::println("msg.parvalue[2] = <{}>", p2.value_or(std::chrono::seconds{})); + + + std::print("msg.parvalue[3] = <"); + auto p3 = msg2.paramValue(3); + if (p3.has_value()) { + for (auto const& el : p3.value()) { + std::print("{} ", el); + } + } + std::println(">"); + + + std::println("msg.par[1-2] joined = <{}>", msg2.params(1, 2)); + + auto vv = msg2.params>(1, 3); + std::print("msg.par[1-3] array = <"); + for (auto const& el : vv) { + std::print("{} ", el); + } + std::println(">"); + + + std::println("\n\n"); + + mcc::impl::MccSkyPoint spt(mcc::impl::MccSkyRADEC_APP{"10:00:00.0"_hms, 12.098687_degs}); + + msg2.construct("ACK", "MOUNT", spt); + std::println("msg2.bytes = <{}>", msg2.byteRepr()); + + auto spt_d = msg2.paramValue(1); + + if (spt_d){ + std::println("msg2.parvalue(1).epoch() = {}", spt_d->epoch().MJD()+mcc::MCC_MJD_ZERO); + } else { + std::println("cannot deserialize MccSkyPoint value!"); + } + + return 0; +}