#pragma once /**************************************************************************************** * * * MOUNT CONTROL COMPONENTS LIBRARY * * * * * * COMMON DEFINITIONS FOR DATA SERIALIZATION/DESERIALIZATION * * * ****************************************************************************************/ #include "mcc_concepts.h" #include "mcc_error.h" #include "mcc_traits.h" namespace mcc { /* celestial angle serialization */ enum class MccSerializedAngleFormat { MCC_SERIALIZED_FORMAT_DEGREES, // degrees as floating-point number MCC_SERIALIZED_FORMAT_SXGM_HOURS, // sexagesimal representation: hours:mins:secs MCC_SERIALIZED_FORMAT_SXGM_DEGS, // sexagesimal representation: degs:arcmins:arcsecs MCC_SERIALIZED_FORMAT_UNKNOWN }; static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR = "SRANG-FORMAT-DEGREES"; static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR = "SRANG-FORMAT-SXGM_HOURDEG"; static constexpr std::string_view MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR = "SRANG-FORMAT-SXGM_DEGDEG"; static constexpr std::string_view MccSerializedAngleFormatToStr(MccSerializedAngleFormat fmt) { return fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES ? MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR : fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS ? MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR : fmt == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS ? MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR : MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR; } template static constexpr MccSerializedAngleFormat MccSerializedAngleFormatStrToValue(R&& str) { if constexpr (std::is_array_v>) { return MccSerializedAngleFormatStrToValue(std::string_view{str}); } const auto hash = mcc::utils::FNV1aHash(std::forward(str)); return hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_DEGREES_STR) ? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES : hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_SXGM_HOURS_STR) ? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS : hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_ANG_FORMAT_SXGM_DEGS_STR) ? MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS : MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_UNKNOWN; } /* coordinates pair serialization */ enum class MccSerializedCoordPairFormat { MCC_SERIALIZED_FORMAT_DEGREES, // both angles are in degrees as floating-point number MCC_SERIALIZED_FORMAT_SXGM_HOURDEG, // X is in hour and Y is in degree sexagesimal representation MCC_SERIALIZED_FORMAT_SXGM_DEGDEG, // both angles are in sexagesimal degrees MCC_SERIALIZED_FORMAT_UNKNOWN }; static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_DEGREES_STR = "SRCP-FORMAT-DEGREES"; static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR = "SRCP-FORMAT-SXGM_HOURDEG"; static constexpr std::string_view MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR = "SRCP-FORMAT-SXGM_DEGDEG"; static constexpr std::string_view MccSerializedCoordPairFormatToStr(MccSerializedCoordPairFormat fmt) { return fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES ? MCC_SERIALIZED_CP_FORMAT_DEGREES_STR : fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG ? MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR : fmt == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG ? MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR : MCC_SERIALIZED_CP_FORMAT_DEGREES_STR; } template static constexpr MccSerializedCoordPairFormat MccSerializedCoordPairFormatStrToValue(R&& str) { if constexpr (std::is_array_v>) { return MccSerializedCoordPairFormatStrToValue(std::string_view{str}); } const auto hash = mcc::utils::FNV1aHash(std::forward(str)); return hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_DEGREES_STR) ? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES : hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_SXGM_HOURDEG_STR) ? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG : hash == mcc::utils::FNV1aHash(MCC_SERIALIZED_CP_FORMAT_SXGM_DEGDEG_STR) ? MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG : MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_UNKNOWN; } /* precision of representation of serialized celestial angle/coordinates pair */ struct MccSerializedAngleFormatPrec { uint8_t hour_prec = 2; // number of decimal places in hour seconds (sexagesimal format) uint8_t deg_prec = 1; // number of decimal places in arcseconds (sexagesimal format) // slightly better than 0.1 arcsecond precision uint8_t decimals = 6; // number of decimal places in degrees (floating-point number format) // if 0, then number of decimal places is according to formating rules of 'double' type }; enum class MccTimePointFormat { MCC_TIMEPOINT_FORMAT_DATE, // UTC date MCC_TIMEPOINT_FORMAT_MJD, // MJD MCC_TIMEPOINT_FORMAT_JD, // JD MCC_TIMEPOINT_FORMAT_JEPOCH, // Julian epoch MCC_TIMEPOINT_FORMAT_UNKNOWN }; static constexpr std::string_view MCC_TIMEPOINT_FORMAT_DATE_STR = "TP-FORMAT-DATE"; static constexpr std::string_view MCC_TIMEPOINT_FORMAT_MJD_STR = "TP-FORMAT-MJD"; static constexpr std::string_view MCC_TIMEPOINT_FORMAT_JD_STR = "TP-FORMAT-JD"; static constexpr std::string_view MCC_TIMEPOINT_FORMAT_JEPOCH_STR = "TP-FORMAT-JEPOCH"; static constexpr std::string_view MccTimePointFormatToStr(MccTimePointFormat fmt) { return fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE ? MCC_TIMEPOINT_FORMAT_DATE_STR : fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD ? MCC_TIMEPOINT_FORMAT_MJD_STR : fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD ? MCC_TIMEPOINT_FORMAT_JD_STR : fmt == MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH ? MCC_TIMEPOINT_FORMAT_JEPOCH_STR : MCC_TIMEPOINT_FORMAT_MJD_STR; } template static constexpr MccTimePointFormat MccTimePointFormatStrToValue(R&& str) { if constexpr (std::is_array_v>) { return MccTimePointFormatStrToValue(std::string_view{str}); } const auto hash = mcc::utils::FNV1aHash(std::forward(str)); return hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_DATE_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE : hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_MJD_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD : hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_JD_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD : hash == mcc::utils::FNV1aHash(MCC_TIMEPOINT_FORMAT_JEPOCH_STR) ? MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH : MccTimePointFormat::MCC_TIMEPOINT_FORMAT_UNKNOWN; } /* SERIALIZATION/DESERIALIZATION PROCESS TUNING PARAMETERS */ // delimiter between items of serializing values sequence static constexpr std::string_view MCC_SERIALIZING_DEFAULT_SEQ_DELIMITER{";"}; // delimiter between items of aggregative (multi-element) serializing value static constexpr std::string_view MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER{","}; template concept mcc_serialization_params_c = std::copyable && requires(T t) { requires traits::mcc_output_char_range; requires traits::mcc_output_char_range; requires std::same_as; requires std::same_as; requires std::same_as; requires std::same_as; // a format string for mcc_systime_c types (std;:chrono::sys_time) requires std::same_as; // if true - normalize angle in sexagesimal format (to control rounding) // (to avoid something like "24:00:00.0" for sexagesimal 'hours:minutes:seconds' format) requires std::convertible_to; // if true - interpretate serialized angle in sexagesimal format as 'hours:minutes:seconds' // otherwise as 'degrees:arcmins:arcsecs' requires std::convertible_to; }; /* SERIALIZER/DESERIALIZER CONCEPTS */ template struct mcc_serializer_interface_t { virtual ~mcc_serializer_interface_t() = default; typedef RetT error_t; template SelfT, traits::mcc_output_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R& output, ValueT const& value) { return std::forward(self)(output, value); } template SelfT, traits::mcc_output_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R& output, ValueT const& value, mcc_serialization_params_c auto const& params) { return std::forward(self)(output, value, params); } protected: mcc_serializer_interface_t() = default; }; template concept mcc_serializer_c = std::derived_from> && requires(T t, const T t_const) { // static const variable with name of the serializer requires std::formattable && std::is_const_v; // // must define a type "params_t" // requires mcc_serialization_params_c; // { t.setParams(std::declval()) }; // { t_const.getParams() } -> std::same_as; }; template struct mcc_deserializer_interface_t { virtual ~mcc_deserializer_interface_t() = default; typedef RetT error_t; template SelfT, traits::mcc_input_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R const& input, ValueT& value) { return std::forward(self)(input, value); } template SelfT, traits::mcc_input_char_range R, typename ValueT> RetT operator()(this SelfT&& self, R const& input, ValueT& value, mcc_serialization_params_c auto& params) { return std::forward(self)(input, value, params); } protected: mcc_deserializer_interface_t() = default; }; template concept mcc_deserializer_c = std::derived_from> && requires(T t, const T t_const) { // static const variable with name of the deserializer requires std::formattable && std::is_const_v; // // must define a type "params_t" // requires mcc_serialization_params_c; // { t.setParams(std::declval()) }; // { t_const.getParams() } -> std::same_as; }; /* BASE CLASS IMPLEMENTATION FOR SERIALIZER/DESERIALIZER */ namespace impl { // default definition of serialization/deserialization process parameters structure struct mcc_serialization_params_t { std::string seq_delim{MCC_SERIALIZING_DEFAULT_SEQ_DELIMITER}; std::string elem_delim{MCC_SERIALIZING_DEFAULT_ELEM_DELIMITER}; MccSerializedAngleFormat angle_format{MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES}; MccSerializedAngleFormatPrec angle_prec{MccSerializedAngleFormatPrec{.hour_prec = 2, .deg_prec = 1, .decimals = 6}}; MccSerializedCoordPairFormat coordpair_format{MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG}; MccTimePointFormat timepoint_format{MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE}; std::string_view systime_format{"{:%FT%T}"}; bool norm_sxgm{false}; bool sxgm_hms{false}; }; static_assert(mcc_serialization_params_c, "!!!"); namespace details { template struct _params_manipulator_t { virtual ~_params_manipulator_t() = default; typedef ParamsT params_t; template void setParams(p_t const& pars) { if constexpr (std::same_as) { _params = pars; } else { _params.seq_delim = pars.seq_delim; _params.elem_delim = pars.elem_delim; _params.coordpair_format = pars.coordpair_format; _params.angle_prec = pars.angle_prec; _params.timepoint_format = pars.timepoint_format; _params.norm_sxgm = pars.norm_sxgm; _params.sxgm_hms = pars.sxgm_hms; } } template requires(!std::same_as) p_t getParams() const { p_t pars; pars.seq_delim = _params.seq_delim; pars.elem_delim = _params.elem_delim; pars.coordpair_format = _params.coordpair_format; pars.angle_prec = _params.angle_prec; pars.timepoint_format = _params.timepoint_format; pars.norm_sxgm = _params.norm_sxgm; pars.sxgm_hms = _params.sxgm_hms; return pars; } params_t getParams() const { return _params; } protected: _params_manipulator_t() = default; params_t _params; }; } // namespace details struct MccDeserializerBase : mcc_deserializer_interface_t { virtual ~MccDeserializerBase() = default; using typename mcc_deserializer_interface_t::error_t; protected: MccDeserializerBase() = default; }; // template // struct MccSerializerBase : mcc_serializer_interface_t, details::_params_manipulator_t { // virtual ~MccSerializerBase() = default; // using typename mcc_serializer_interface_t::error_t; // using typename details::_params_manipulator_t::params_t; // protected: // MccSerializerBase() = default; // }; // template // struct MccDeserializerBase : mcc_deserializer_interface_t, details::_params_manipulator_t { // virtual ~MccDeserializerBase() = default; // using typename mcc_deserializer_interface_t::error_t; // using typename details::_params_manipulator_t::params_t; // protected: // MccDeserializerBase() = default; // }; } // namespace impl } // namespace mcc