...
This commit is contained in:
@@ -51,17 +51,6 @@ endif()
|
||||
|
||||
# ******* ERFA LIBRARY *******
|
||||
|
||||
find_program(MESON_PROG NAMES meson HINTS ENV PATHS)
|
||||
|
||||
if (NOT MESON_PROG)
|
||||
message(FATAL "meson executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
find_program(NINJA_PROG NAMES ninja ninja-build)
|
||||
|
||||
if (NOT NINJA_PROG)
|
||||
message(FATAL "ninja executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
@@ -92,6 +81,18 @@ if (NOT ERFALIB_FOUND)
|
||||
# set(CACHE{ERFALIB_LIBRARY_DIRS} TYPE PATH VALUE "${CMAKE_BINARY_DIR}/erfa_lib")
|
||||
# set(CACHE{ERFALIB_LIBRARIES} TYPE STRING VALUE "erfa;m")
|
||||
|
||||
find_program(MESON_PROG NAMES meson HINTS ENV PATHS)
|
||||
|
||||
if (NOT MESON_PROG)
|
||||
message(FATAL "meson executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
find_program(NINJA_PROG NAMES ninja ninja-build)
|
||||
|
||||
if (NOT NINJA_PROG)
|
||||
message(FATAL "ninja executable can not be found!!!")
|
||||
endif()
|
||||
|
||||
|
||||
FetchContent_Declare(erfalib_project
|
||||
GIT_REPOSITORY "https://github.com/liberfa/erfa.git"
|
||||
|
||||
28
mcc_angle.h
28
mcc_angle.h
@@ -715,21 +715,21 @@ static constexpr MccCoordPairKind MccCoordStrToPairKind(R&& spair)
|
||||
}
|
||||
|
||||
|
||||
enum class MccCoordinatePairRep : int {
|
||||
MCC_COORDPAIR_REP_DEGREES, // both angles are in decimal degrees
|
||||
MCC_COORDPAIR_REP_SXGM_HOURDEG, // X is in hour and Y is in degree sexagesimal representation
|
||||
MCC_COORDPAIR_REP_SXGM_DEGDEG // both angles are in sexagesimal degrees
|
||||
};
|
||||
// enum class MccCoordinatePairRep : int {
|
||||
// MCC_COORDPAIR_REP_DEGREES, // both angles are in decimal degrees
|
||||
// MCC_COORDPAIR_REP_SXGM_HOURDEG, // X is in hour and Y is in degree sexagesimal representation
|
||||
// MCC_COORDPAIR_REP_SXGM_DEGDEG // both angles are in sexagesimal degrees
|
||||
// };
|
||||
|
||||
|
||||
// default wide-acceptable sexagesimal representation
|
||||
static constexpr MccCoordinatePairRep MccCoordinatePairToSxgmRep(MccCoordPairKind kind)
|
||||
{
|
||||
return kind == MccCoordPairKind::COORDS_KIND_AZALT || kind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
kind == MccCoordPairKind::COORDS_KIND_XY || kind == MccCoordPairKind::COORDS_KIND_LONLAT ||
|
||||
kind == MccCoordPairKind::COORDS_KIND_GENERIC
|
||||
? MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_DEGDEG
|
||||
: MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG; // RA-DEC or HA-DEC
|
||||
}
|
||||
// // default wide-acceptable sexagesimal representation
|
||||
// static constexpr MccCoordinatePairRep MccCoordinatePairToSxgmRep(MccCoordPairKind kind)
|
||||
// {
|
||||
// return kind == MccCoordPairKind::COORDS_KIND_AZALT || kind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
// kind == MccCoordPairKind::COORDS_KIND_XY || kind == MccCoordPairKind::COORDS_KIND_LONLAT ||
|
||||
// kind == MccCoordPairKind::COORDS_KIND_GENERIC
|
||||
// ? MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_DEGDEG
|
||||
// : MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG; // RA-DEC or HA-DEC
|
||||
// }
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
301
mcc_deser.h
301
mcc_deser.h
@@ -1,301 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_serialization_common.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccDeserializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_DESERIALIZER,
|
||||
ERROR_INVALID_SERIALIZED_VALUE,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccDeserializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
// error category
|
||||
struct MccDeserializerCategory : public std::error_category {
|
||||
MccDeserializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-DESERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccDeserializerErrorCode err = static_cast<MccDeserializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccDeserializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER:
|
||||
return "error returned by underlying deserializer";
|
||||
case MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE:
|
||||
return "invalid serialized value";
|
||||
case MccDeserializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccDeserializerCategory& get()
|
||||
{
|
||||
static const MccDeserializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccDeserializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccDeserializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* BASE DESERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
|
||||
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<MccError> {
|
||||
using typename mcc_deserializer_interface_t<MccError>::error_t;
|
||||
|
||||
virtual ~MccDeserializerBase() = default;
|
||||
|
||||
|
||||
protected:
|
||||
MccDeserializerBase() = default;
|
||||
|
||||
//
|
||||
// empty == true, if the 'input' is empty or if all elements consist of only spaces
|
||||
//
|
||||
static std::vector<std::string_view> splitValueIntoElements(traits::mcc_input_char_range auto const& input,
|
||||
mcc_serialization_params_c auto const& params,
|
||||
bool& empty)
|
||||
{
|
||||
static_assert(std::ranges::contiguous_range<decltype(input)>, "NOT IMPLEMENTED FOR NON-CONTIGUIUS RANGES!!!");
|
||||
|
||||
std::vector<std::string_view> res;
|
||||
|
||||
if (std::ranges::size(input)) {
|
||||
empty = true;
|
||||
|
||||
std::ranges::for_each(std::views::split(input, params.elem_delim), [&res, &empty](auto const& el) {
|
||||
std::back_inserter(res) = utils::trimSpaces(std::string_view{el.begin(), el.end()});
|
||||
if (empty && res.back().size()) {
|
||||
empty = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
empty = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename VT, std::ranges::output_range<VT> R, typename... DeserParamsT>
|
||||
static error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
traits::mcc_input_char_range auto const& input,
|
||||
R& r,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
if (std::ranges::size(input) == 0) { // ignore an empty input, just return empty range?!!
|
||||
r = R{};
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, params.seq_delim);
|
||||
VT val;
|
||||
|
||||
auto it = r.begin();
|
||||
for (auto const& el : r_str) {
|
||||
auto err = dsr(el, val, std::forward<DeserParamsT>(params)...);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
if (it == r.end()) {
|
||||
std::back_inserter(r) = val;
|
||||
it = r.end();
|
||||
} else {
|
||||
*it = val;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION */
|
||||
|
||||
|
||||
template <typename VT>
|
||||
struct MccDeserializer : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-FALLBACK-DESERIALIZER"};
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(utils::trimSpaces(input));
|
||||
if (!v.has_value()) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
value = v.value();
|
||||
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
|
||||
VT r;
|
||||
if constexpr (traits::mcc_array_c<VT>) {
|
||||
size_t N =
|
||||
std::ranges::size(r) <= std::ranges::size(input) ? std::ranges::size(r) : std::ranges::size(input);
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
r[i] = input[i];
|
||||
}
|
||||
if (std::ranges::size(r) > N) {
|
||||
for (size_t i = N; i < std::ranges::size(r); ++i) {
|
||||
r[i] = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::ranges::copy(input, std::back_inserter(r));
|
||||
}
|
||||
|
||||
value = r;
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using el_t = std::ranges::range_value_t<VT>;
|
||||
|
||||
static_assert(std::ranges::output_range<VT, el_t>, "INVALID RANGE TYPE!!!");
|
||||
|
||||
// no reference or constants allowed
|
||||
static_assert(std::is_reference_v<el_t> || std::is_const_v<el_t>, "INVALID RANGE ELEMENT TYPE!!!");
|
||||
|
||||
MccDeserializer<el_t> dsr;
|
||||
return deserializingRange<el_t>(dsr, input, value, params);
|
||||
} else if constexpr (traits::mcc_time_duration_c<VT>) {
|
||||
typename VT::rep vd;
|
||||
|
||||
MccDeserializer<typename VT::rep> dsr;
|
||||
|
||||
auto err = dsr(trimSpaces(input), vd, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
value = VT{vd};
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED VALUE TYPE!!!");
|
||||
}
|
||||
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
template <mcc_coord_epoch_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-COORD-EPOCH-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
bool ok = value.fromCharRange(input);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> && mcc_angle_c<VT>)
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-ANGLE-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
bool hms = params.angle_format == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-SKYPOINT-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
// valid format: X<elem-delim>Y[<elem-delim>TIME-POINT<elem-delim>PAIR-KIND]
|
||||
// X<elem-delim>Y (assumed RADEC_ICRS and J2000.0 epoch)
|
||||
|
||||
bool empty;
|
||||
|
||||
auto elems = MccDeserializerBase::splitValueIntoElements(input, params, empty);
|
||||
|
||||
if (empty || (elems.size() < 2) || (elems.size() == 3)) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
MccCoordPairKind pair_kind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
MccCelestialCoordEpoch epoch; // J2000.0
|
||||
|
||||
MccAngle x, y;
|
||||
MccDeserializer<MccAngle> dsr_ang;
|
||||
|
||||
typename MccDeserializer<MccAngle>::error_t dsr_err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -1,23 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF DESERIALIZER CLASSES *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <string_view>
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_error.h"
|
||||
#include "mcc_serialization_common.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
@@ -89,34 +76,11 @@ inline std::error_code make_error_code(MccDeserializerErrorCode ec)
|
||||
}
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_deserializer_interface_t {
|
||||
virtual ~mcc_deserializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
/* BASE DESERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
|
||||
|
||||
template <std::derived_from<mcc_deserializer_interface_t> SelfT,
|
||||
traits::mcc_input_char_range R,
|
||||
typename ValueT,
|
||||
typename... DeserParamsT>
|
||||
RetT operator()(this SelfT&& self, R const& input, ValueT& value, DeserParamsT&&... params)
|
||||
{
|
||||
return std::forward<SelfT>(self)(input, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_deserializer_interface_t() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_deserializer_c = std::derived_from<T, mcc_deserializer_interface_t<typename T::error_t>>;
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<impl::MccError>, utils::mcc_elem_sequence_with_delim_t {
|
||||
using typename mcc_deserializer_interface_t<impl::MccError>::error_t;
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<MccError> {
|
||||
using typename mcc_deserializer_interface_t<MccError>::error_t;
|
||||
|
||||
virtual ~MccDeserializerBase() = default;
|
||||
|
||||
@@ -127,14 +91,18 @@ protected:
|
||||
//
|
||||
// empty == true, if the 'input' is empty or if all elements consist of only spaces
|
||||
//
|
||||
std::vector<std::string_view> splitAggregateValue(traits::mcc_input_char_range auto const& input, bool& empty) const
|
||||
static std::vector<std::string_view> splitValueIntoElements(traits::mcc_input_char_range auto const& input,
|
||||
mcc_serialization_params_c auto const& params,
|
||||
bool& empty)
|
||||
{
|
||||
static_assert(std::ranges::contiguous_range<decltype(input)>, "NOT IMPLEMENTED FOR NON-CONTIGUIUS RANGES!!!");
|
||||
|
||||
std::vector<std::string_view> res;
|
||||
|
||||
if (std::ranges::size(input)) {
|
||||
empty = true;
|
||||
|
||||
std::ranges::for_each(std::views::split(input, this->_elementDelimiter), [&res, &empty](auto const& el) {
|
||||
std::ranges::for_each(std::views::split(input, params.elem_delim), [&res, &empty](auto const& el) {
|
||||
std::back_inserter(res) = utils::trimSpaces(std::string_view{el.begin(), el.end()});
|
||||
if (empty && res.back().size()) {
|
||||
empty = false;
|
||||
@@ -148,17 +116,17 @@ protected:
|
||||
}
|
||||
|
||||
template <typename VT, std::ranges::output_range<VT> R, typename... DeserParamsT>
|
||||
error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
static error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
traits::mcc_input_char_range auto const& input,
|
||||
R& r,
|
||||
DeserParamsT&&... params) const
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
if (std::ranges::size(input) == 0) { // ignore an empty input, just return empty range?!!
|
||||
r = R{};
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, _seqDelimiter);
|
||||
auto r_str = std::views::split(input, params.seq_delim);
|
||||
VT val;
|
||||
|
||||
auto it = r.begin();
|
||||
@@ -181,21 +149,21 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION */
|
||||
|
||||
/* fallback template: basic deserializer */
|
||||
|
||||
template <typename VT>
|
||||
class MccDeserializer : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
struct MccDeserializer : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-FALLBACK-DESERIALIZER"};
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(utils::trimSpaces(input));
|
||||
@@ -232,13 +200,13 @@ public:
|
||||
static_assert(std::is_reference_v<el_t> || std::is_const_v<el_t>, "INVALID RANGE ELEMENT TYPE!!!");
|
||||
|
||||
MccDeserializer<el_t> dsr;
|
||||
return deserializingRange<el_t>(dsr, input, value);
|
||||
return deserializingRange<el_t>(dsr, input, value, params);
|
||||
} else if constexpr (traits::mcc_time_duration_c<VT>) {
|
||||
typename VT::rep vd;
|
||||
|
||||
MccDeserializer<typename VT::rep> dsr;
|
||||
|
||||
auto err = dsr(trimSpaces(input), vd);
|
||||
auto err = dsr(trimSpaces(input), vd, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
@@ -254,94 +222,69 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
template <mcc_coord_epoch_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-COORD-EPOCH-DESERIALIZER"};
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_epoch_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_coord_epoch_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (mcc_coord_epoch_c<VT>) { // scalar
|
||||
bool ok = value.fromCharRange(input);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
return deserializingRange(dsr, input, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> &&
|
||||
(mcc_angle_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_angle_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>)))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
// if hms == true and the input sequence is a sexagesimal string then it interpretates angle as hours:mins:secs
|
||||
// otherwise the input sequence is interpretated as decimal or sexagesimal degrees
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value, bool hms = false)
|
||||
{
|
||||
if constexpr (mcc_angle_c<VT>) { // scalar
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
if constexpr (std::invocable<MccDeserializer<value_t>, decltype(input), VT&, bool>) {
|
||||
// it is assumed here, the angle deserializer has the same behavior as the one implemented above
|
||||
// (that is, it can interpret the third argument as a flag "false/true = only
|
||||
// degrees/hour-like")
|
||||
return deserializingRange<value_t>(dsr, input, value, hms);
|
||||
} else {
|
||||
return deserializingRange<value_t>(dsr, input, value);
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_skypoint_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_skypoint_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
requires(!std::is_arithmetic_v<VT> && mcc_angle_c<VT>)
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-ANGLE-DESERIALIZER"};
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (mcc_skypoint_c<VT>) { // scalar: X[elem-delim]Y{[elem-delim]TIME-POINT[elem-delim]PAIR-KIND}
|
||||
bool empty; // exactly 2 or >3 elements
|
||||
auto elems = splitAggregateValue(input, empty);
|
||||
bool hms = params.angle_format == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-SKYPOINT-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto pars = params;
|
||||
|
||||
// valid format: X<elem-delim>Y[<elem-delim>TIME-POINT<elem-delim>PAIR-KIND]
|
||||
// X<elem-delim>Y (assumed RADEC_ICRS and J2000.0 epoch)
|
||||
|
||||
bool empty;
|
||||
|
||||
auto elems = MccDeserializerBase::splitValueIntoElements(input, params, empty);
|
||||
|
||||
if (empty || (elems.size() < 2) || (elems.size() == 3)) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
@@ -355,8 +298,8 @@ public:
|
||||
|
||||
typename MccDeserializer<MccAngle>::error_t dsr_err;
|
||||
|
||||
if (elems.size() >= 4) { // X, Y, TIME-POINT, PAIR-KIND
|
||||
// first, get pair-kind
|
||||
if (elems.size() > 3) { // full format
|
||||
// deserialize pair kind string
|
||||
pair_kind = MccCoordStrToPairKind(elems[3]);
|
||||
if (pair_kind == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
@@ -369,32 +312,23 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (elems.size() >= 2) { // if == 2: just X and Y (if so it is interpretated as RADEC_ICRS)
|
||||
if (MccCoordinatePairToSxgmRep(pair_kind) == MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG) {
|
||||
// if input X-angle is in sexagesimal from then interpretate it in hours::mins::secs format
|
||||
if constexpr (std::invocable<MccDeserializer<MccAngle>, decltype(elems[0]), MccAngle&, bool>) {
|
||||
// it is assumed here, the angle deserializer has the same behavior as the one implemented above
|
||||
// (that is, it can interpret the third argument as a flag "false/true = only
|
||||
// degrees/hour-like")
|
||||
dsr_err = dsr_ang(elems[0], x, true);
|
||||
// deserialize X and Y
|
||||
if (params.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
} else {
|
||||
dsr_err = dsr_ang(elems[0], x);
|
||||
}
|
||||
} else {
|
||||
dsr_err = dsr_ang(elems[0], x);
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
}
|
||||
|
||||
dsr_err = dsr_ang(elems[0], x, pars);
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
dsr_err = dsr_ang(elems[1], y);
|
||||
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
dsr_err = dsr_ang(elems[1], y, pars);
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (pair_kind) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
@@ -431,15 +365,9 @@ public:
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
return deserializingRange<value_t>(dsr, input, value);
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
445
mcc_deserializer.h.old
Normal file
445
mcc_deserializer.h.old
Normal file
@@ -0,0 +1,445 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF DESERIALIZER CLASSES *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <string_view>
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_error.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccDeserializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_DESERIALIZER,
|
||||
ERROR_INVALID_SERIALIZED_VALUE,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccDeserializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
// error category
|
||||
struct MccDeserializerCategory : public std::error_category {
|
||||
MccDeserializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-DESERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccDeserializerErrorCode err = static_cast<MccDeserializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccDeserializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER:
|
||||
return "error returned by underlying deserializer";
|
||||
case MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE:
|
||||
return "invalid serialized value";
|
||||
case MccDeserializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccDeserializerCategory& get()
|
||||
{
|
||||
static const MccDeserializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccDeserializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccDeserializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_deserializer_interface_t {
|
||||
virtual ~mcc_deserializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
|
||||
template <std::derived_from<mcc_deserializer_interface_t> SelfT,
|
||||
traits::mcc_input_char_range R,
|
||||
typename ValueT,
|
||||
typename... DeserParamsT>
|
||||
RetT operator()(this SelfT&& self, R const& input, ValueT& value, DeserParamsT&&... params)
|
||||
{
|
||||
return std::forward<SelfT>(self)(input, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_deserializer_interface_t() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_deserializer_c = std::derived_from<T, mcc_deserializer_interface_t<typename T::error_t>>;
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<impl::MccError>, utils::mcc_elem_sequence_with_delim_t {
|
||||
using typename mcc_deserializer_interface_t<impl::MccError>::error_t;
|
||||
|
||||
virtual ~MccDeserializerBase() = default;
|
||||
|
||||
|
||||
protected:
|
||||
MccDeserializerBase() = default;
|
||||
|
||||
//
|
||||
// empty == true, if the 'input' is empty or if all elements consist of only spaces
|
||||
//
|
||||
std::vector<std::string_view> splitAggregateValue(traits::mcc_input_char_range auto const& input, bool& empty) const
|
||||
{
|
||||
std::vector<std::string_view> res;
|
||||
|
||||
if (std::ranges::size(input)) {
|
||||
empty = true;
|
||||
|
||||
std::ranges::for_each(std::views::split(input, this->_elementDelimiter), [&res, &empty](auto const& el) {
|
||||
std::back_inserter(res) = utils::trimSpaces(std::string_view{el.begin(), el.end()});
|
||||
if (empty && res.back().size()) {
|
||||
empty = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
empty = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename VT, std::ranges::output_range<VT> R, typename... DeserParamsT>
|
||||
error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
traits::mcc_input_char_range auto const& input,
|
||||
R& r,
|
||||
DeserParamsT&&... params) const
|
||||
{
|
||||
if (std::ranges::size(input) == 0) { // ignore an empty input, just return empty range?!!
|
||||
r = R{};
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, _seqDelimiter);
|
||||
VT val;
|
||||
|
||||
auto it = r.begin();
|
||||
for (auto const& el : r_str) {
|
||||
auto err = dsr(el, val, std::forward<DeserParamsT>(params)...);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
if (it == r.end()) {
|
||||
std::back_inserter(r) = val;
|
||||
it = r.end();
|
||||
} else {
|
||||
*it = val;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
/* fallback template: basic deserializer */
|
||||
|
||||
template <typename VT>
|
||||
class MccDeserializer : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(utils::trimSpaces(input));
|
||||
if (!v.has_value()) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
value = v.value();
|
||||
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
|
||||
VT r;
|
||||
if constexpr (traits::mcc_array_c<VT>) {
|
||||
size_t N =
|
||||
std::ranges::size(r) <= std::ranges::size(input) ? std::ranges::size(r) : std::ranges::size(input);
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
r[i] = input[i];
|
||||
}
|
||||
if (std::ranges::size(r) > N) {
|
||||
for (size_t i = N; i < std::ranges::size(r); ++i) {
|
||||
r[i] = '\0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::ranges::copy(input, std::back_inserter(r));
|
||||
}
|
||||
|
||||
value = r;
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using el_t = std::ranges::range_value_t<VT>;
|
||||
|
||||
static_assert(std::ranges::output_range<VT, el_t>, "INVALID RANGE TYPE!!!");
|
||||
|
||||
// no reference or constants allowed
|
||||
static_assert(std::is_reference_v<el_t> || std::is_const_v<el_t>, "INVALID RANGE ELEMENT TYPE!!!");
|
||||
|
||||
MccDeserializer<el_t> dsr;
|
||||
return deserializingRange<el_t>(dsr, input, value);
|
||||
} else if constexpr (traits::mcc_time_duration_c<VT>) {
|
||||
typename VT::rep vd;
|
||||
|
||||
MccDeserializer<typename VT::rep> dsr;
|
||||
|
||||
auto err = dsr(trimSpaces(input), vd);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
value = VT{vd};
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED VALUE TYPE!!!");
|
||||
}
|
||||
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_epoch_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_coord_epoch_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
{
|
||||
if constexpr (mcc_coord_epoch_c<VT>) { // scalar
|
||||
bool ok = value.fromCharRange(input);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
return deserializingRange(dsr, input, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> &&
|
||||
(mcc_angle_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_angle_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>)))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
// if hms == true and the input sequence is a sexagesimal string then it interpretates angle as hours:mins:secs
|
||||
// otherwise the input sequence is interpretated as decimal or sexagesimal degrees
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value, bool hms = false)
|
||||
{
|
||||
if constexpr (mcc_angle_c<VT>) { // scalar
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
if constexpr (std::invocable<MccDeserializer<value_t>, decltype(input), VT&, bool>) {
|
||||
// it is assumed here, the angle deserializer has the same behavior as the one implemented above
|
||||
// (that is, it can interpret the third argument as a flag "false/true = only
|
||||
// degrees/hour-like")
|
||||
return deserializingRange<value_t>(dsr, input, value, hms);
|
||||
} else {
|
||||
return deserializingRange<value_t>(dsr, input, value);
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_skypoint_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_skypoint_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
{
|
||||
if constexpr (mcc_skypoint_c<VT>) { // scalar: X[elem-delim]Y{[elem-delim]TIME-POINT[elem-delim]PAIR-KIND}
|
||||
bool empty; // exactly 2 or >3 elements
|
||||
auto elems = splitAggregateValue(input, empty);
|
||||
|
||||
if (empty || (elems.size() < 2) || (elems.size() == 3)) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
MccCoordPairKind pair_kind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
MccCelestialCoordEpoch epoch; // J2000.0
|
||||
|
||||
MccAngle x, y;
|
||||
MccDeserializer<MccAngle> dsr_ang;
|
||||
|
||||
typename MccDeserializer<MccAngle>::error_t dsr_err;
|
||||
|
||||
if (elems.size() >= 4) { // X, Y, TIME-POINT, PAIR-KIND
|
||||
// first, get pair-kind
|
||||
pair_kind = MccCoordStrToPairKind(elems[3]);
|
||||
if (pair_kind == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
// epoch
|
||||
bool ok = epoch.fromCharRange(elems[2]);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (elems.size() >= 2) { // if == 2: just X and Y (if so it is interpretated as RADEC_ICRS)
|
||||
if (MccCoordinatePairToSxgmRep(pair_kind) == MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG) {
|
||||
// if input X-angle is in sexagesimal from then interpretate it in hours::mins::secs format
|
||||
if constexpr (std::invocable<MccDeserializer<MccAngle>, decltype(elems[0]), MccAngle&, bool>) {
|
||||
// it is assumed here, the angle deserializer has the same behavior as the one implemented above
|
||||
// (that is, it can interpret the third argument as a flag "false/true = only
|
||||
// degrees/hour-like")
|
||||
dsr_err = dsr_ang(elems[0], x, true);
|
||||
} else {
|
||||
dsr_err = dsr_ang(elems[0], x);
|
||||
}
|
||||
} else {
|
||||
dsr_err = dsr_ang(elems[0], x);
|
||||
}
|
||||
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
dsr_err = dsr_ang(elems[1], y);
|
||||
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (pair_kind) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
value.from(MccSkyRADEC_ICRS{(double)x, (double)y});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS:
|
||||
value.from(MccSkyRADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
||||
value.from(MccSkyRADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS:
|
||||
value.from(MccSkyHADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
||||
value.from(MccSkyHADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD:
|
||||
value.from(MccSkyAZZD{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT:
|
||||
value.from(MccSkyAZALT{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_XY:
|
||||
value.from(MccGenXY{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC:
|
||||
value.from(MccCoordPair{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_LONLAT:
|
||||
value.from(MccGeoLONLAT{(double)x, (double)y});
|
||||
break;
|
||||
default:
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
return deserializingRange<value_t>(dsr, input, value);
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
693
mcc_ser.h
693
mcc_ser.h
@@ -1,693 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_serialization_common.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccSerializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_SERIALIZER,
|
||||
ERROR_INVALID_EPOCH,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccSerializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// error category
|
||||
struct MccSerializerCategory : public std::error_category {
|
||||
MccSerializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-SERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccSerializerErrorCode err = static_cast<MccSerializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccSerializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER:
|
||||
return "error returned by underlying serializer";
|
||||
case MccSerializerErrorCode::ERROR_INVALID_EPOCH:
|
||||
return "invalid coordinate epoch";
|
||||
case MccSerializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccSerializerCategory& get()
|
||||
{
|
||||
static const MccSerializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccSerializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccSerializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
/* BASE SERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
|
||||
|
||||
struct MccSerializerBase : mcc_serializer_interface_t<MccError> {
|
||||
virtual ~MccSerializerBase() = default;
|
||||
|
||||
using typename mcc_serializer_interface_t<MccError>::error_t;
|
||||
|
||||
protected:
|
||||
MccSerializerBase() = default;
|
||||
|
||||
enum CoordType { CO_LON, CO_LAT };
|
||||
|
||||
static void addElemDelimiter(traits::mcc_output_char_range auto& output,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
std::format_to(std::back_inserter(output), "{}", params.elem_delim);
|
||||
}
|
||||
|
||||
|
||||
static void addSeqDelimiter(traits::mcc_output_char_range auto& output,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
std::format_to(std::back_inserter(output), "{}", params.seq_delim);
|
||||
}
|
||||
|
||||
|
||||
// set serialized angle format according to coordinates pair format and type of
|
||||
// serializing mcc_coord_pair_c::pairKind
|
||||
template <MccCoordPairKind PAIRKIND, CoordType TYPE = MccSerializerBase::CO_LON>
|
||||
static void angleFormatFromCoordPairType(mcc_serialization_params_c auto& pars)
|
||||
{
|
||||
if (pars.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_DEGREES) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES;
|
||||
} else { // format to sexagesimal form according to celestial coordinate type
|
||||
if constexpr (TYPE == MccSerializerBase::CO_LON) {
|
||||
if (pars.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGDEG) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
} else if (pars.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG) {
|
||||
if constexpr (PAIRKIND == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
PAIRKIND == MccCoordPairKind::COORDS_KIND_AZALT ||
|
||||
PAIRKIND == MccCoordPairKind::COORDS_KIND_XY ||
|
||||
PAIRKIND == MccCoordPairKind::COORDS_KIND_GENERIC) { // azimuth is in degrees
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
} else { // RA or HA
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
}
|
||||
} else {
|
||||
// !!!!!!!!!!!!!!!!!!
|
||||
}
|
||||
} else { // Y-coordinates (co-latitude one, DEC, ALT, ZD, generic X) is always in degrees for celestial
|
||||
// point
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VT, typename R>
|
||||
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
|
||||
static error_t serializeRange(mcc_serializer_c auto& sr,
|
||||
R const& r,
|
||||
traits::mcc_output_char_range auto& output,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
size_t i = 0, N = std::ranges::size(r);
|
||||
|
||||
for (auto const& el : r) {
|
||||
auto err = sr(output, el, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
if (++i < N) {
|
||||
MccSerializerBase::addSeqDelimiter(output, params);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION */
|
||||
|
||||
template <typename VT>
|
||||
struct MccSerializer : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-FALLBACK-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
if constexpr (std::formattable<VT, char>) {
|
||||
} else if constexpr (std::convertible_to<VT, std::string>) {
|
||||
auto err = MccSerializer<std::string>{}(output, static_cast<std::string>(value), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
|
||||
// special range (character sequence)
|
||||
if constexpr (std::same_as<value_t, char>) {
|
||||
std::string str;
|
||||
std::ranges::copy(value, std::back_inserter(str));
|
||||
|
||||
auto err = MccSerializer<std::string>{}(output, str, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
} else {
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
return MccSerializerBase::serializeRange<value_t>(sr, value, output, params);
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
/* std::chrono::sys_time variants and its sequence */
|
||||
|
||||
template <typename VT>
|
||||
requires traits::mcc_systime_c<VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
constexpr static std::string_view serializerName{"MCC-SYSTIME-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::vformat_to(std::back_inserter(output), params.systime_format, std::make_format_args(value));
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> && mcc_angle_c<VT>)
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-ANGLE-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
double v = (double)value; // radians (see mcc_angle_c concept)
|
||||
std::string sgm;
|
||||
|
||||
switch (params.angle_format) {
|
||||
case MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_DEGREES:
|
||||
v *= MCC_RADS_TO_DEGRESS;
|
||||
return MccSerializer<double>{}(output, v, params);
|
||||
case MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS:
|
||||
if (params.norm_sxgm) {
|
||||
sgm = utils::rad2sxg<true>(v, false, params.angle_prec.deg_prec);
|
||||
} else {
|
||||
sgm = utils::rad2sxg<false>(v, false, params.angle_prec.deg_prec);
|
||||
}
|
||||
|
||||
break;
|
||||
case MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS:
|
||||
if (params.norm_sxgm) {
|
||||
sgm = utils::rad2sxg<true>(v, true, params.angle_prec.hour_prec);
|
||||
} else {
|
||||
sgm = utils::rad2sxg<false>(v, true, params.angle_prec.hour_prec);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto err = MccSerializer<std::string>{}(output, sgm, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <mcc_coord_epoch_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-COORD-EPOCH-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
double jd;
|
||||
|
||||
switch (params.timepoint_format) {
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_DATE: {
|
||||
auto tp = value.UTC();
|
||||
auto err = MccSerializer<decltype(tp)>{}(output, tp, params);
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JEPOCH: {
|
||||
auto ep = value.JEpoch();
|
||||
auto err = MccSerializer<decltype(ep)>{}(output, ep, params);
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_JD:
|
||||
jd = value.MJD() + MCC_J2000_MJD;
|
||||
break;
|
||||
case MccTimePointFormat::MCC_TIMEPOINT_FORMAT_MJD:
|
||||
jd = value.MJD();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
auto err = MccSerializer<double>{}(output, jd, params);
|
||||
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_coord_pair_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-COORD-PAIR-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto pars = params;
|
||||
|
||||
pars.norm_sxgm = true;
|
||||
pars.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
|
||||
// X-coordinate
|
||||
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars);
|
||||
|
||||
auto err = MccSerializer<MccAngle>{}(output, value.x(), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
|
||||
pars.norm_sxgm = false; // do not normalize co-latitude angle
|
||||
|
||||
// Y-coordinate
|
||||
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LAT>(pars);
|
||||
|
||||
err = MccSerializer<MccAngle>{}(output, value.y(), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
|
||||
// epoch
|
||||
auto ep = value.epoch();
|
||||
auto ep_err = MccSerializer<decltype(ep)>{}(output, ep, params);
|
||||
if (ep_err) {
|
||||
return mcc_deduced_err(ep_err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, params);
|
||||
|
||||
// pair kind
|
||||
return mcc_deduced_err(MccSerializer<std::string_view>{}(output, MccCoordPairKindToStr(VT::pairKind), params),
|
||||
MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-SKYPOINT-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto serialize_cpair = [&]<typename T>(T& cp) {
|
||||
auto ccte_err = value.to(cp);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
auto err = MccSerializer<T>{}(output, cp, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
|
||||
switch (value.pairKind()) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS: {
|
||||
MccSkyRADEC_ICRS cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS: {
|
||||
MccSkyRADEC_OBS cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP: {
|
||||
MccSkyRADEC_APP cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS: {
|
||||
MccSkyHADEC_OBS cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP: {
|
||||
MccSkyHADEC_APP cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD: {
|
||||
MccSkyAZZD cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT: {
|
||||
MccSkyAZALT cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_XY: {
|
||||
MccGenXY cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC: {
|
||||
MccGenXY cp;
|
||||
return serialize_cpair(cp);
|
||||
}
|
||||
default:
|
||||
// !!!!!!!!!!!!
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_telemetry_data_c VT>
|
||||
struct MccSerializer<VT> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-TELEMETRY-DATA-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
// FORMAT: RA_OBS_MOUNT, DEC_OBS_MOUNT, RA_APP_MOUNT, DEC_APP_MOUNT, HA_APP_MOUNT, AZ_MOUNT, ZD_MOUNT,
|
||||
// REFR_CORR_MOUNT, ENC_X, ENC_Y, PCM_X, PCM_Y, RA_APP_TAG, DEC_APP_TAG, AZ_TAG, ZD_TAG, LAST, EO, TIMEPOINT,
|
||||
// STATUS
|
||||
|
||||
// NOTE: One must assume that the returned RA coordinates are in format of underlying celestial coordinate
|
||||
// transformation engine used in the mcc_skypoint_c class implementation. E.g. ERFA-library uses the
|
||||
// CIO-based representation of RA
|
||||
|
||||
auto pars_h = params;
|
||||
|
||||
auto pars_d = params;
|
||||
|
||||
|
||||
pars_h.norm_sxgm = true;
|
||||
pars_h.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
pars_d.norm_sxgm = true;
|
||||
pars_d.coordpair_format = MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
|
||||
MccSkyRADEC_OBS rd_obs;
|
||||
MccSkyRADEC_APP rd_app;
|
||||
MccSkyHADEC_APP hd_app;
|
||||
MccSkyAZZD azzd;
|
||||
|
||||
// quantities in hour representation
|
||||
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars_h);
|
||||
|
||||
// quantities in degree representation
|
||||
MccSerializerBase::angleFormatFromCoordPairType<VT::pairKind, MccSerializerBase::CO_LON>(pars_d);
|
||||
|
||||
MccSerializer<MccAngle> ang_sr;
|
||||
|
||||
// RA_OBS_MOUNT, DEC_OBS_MOUNT
|
||||
auto ccte_err = value.mountPos.toAtSameEpoch(rd_obs);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
auto err = ang_sr(output, rd_obs.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, rd_obs.y(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// RA_APP_MOUNT, DEC_APP_MOUNT
|
||||
ccte_err = value.mountPos.toAtSameEpoch(rd_app);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, rd_app.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, rd_app.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// HA_APP_MOUNT
|
||||
ccte_err = value.mountPos.toAtSameEpoch(hd_app);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, hd_app.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// AZ_MOUNT, ZD_MOUNT
|
||||
ccte_err = value.mountPos.toAtSameEpoch(azzd);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, azzd.x(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, azzd.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// refraction correction
|
||||
|
||||
MccAngle ang;
|
||||
ccte_err = value.mountPos.refractCorrection(&ang);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, ang, pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// encoder X and Y
|
||||
|
||||
err = ang_sr(output, value.hwState.XY.x(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, value.hwState.XY.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// PCM X and Y
|
||||
|
||||
err = ang_sr(output, value.pcmCorrection.pcmX(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, value.pcmCorrection.pcmY(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// RA_APP_TAG, DEC_APP_TAG
|
||||
ccte_err = value.targetPos.toAtSameEpoch(rd_app);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, rd_app.x(), pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, rd_app.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// AZ_TAG, ZD_TAG
|
||||
ccte_err = value.targetPos.toAtSameEpoch(azzd);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, azzd.x(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
err = ang_sr(output, azzd.y(), pars_d);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// LAST, local apparent sideral time
|
||||
|
||||
ccte_err = value.mountPos.appSideralTime(&ang, true);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, ang, pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// EO, equation of origins
|
||||
|
||||
ccte_err = value.mountPos.EO(&ang);
|
||||
if (ccte_err) {
|
||||
return mcc_deduced_err(ccte_err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
err = ang_sr(output, ang, pars_h);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
// coordinates epoch
|
||||
|
||||
auto ep_err = MccSerializer<MccCelestialCoordEpoch>{}(output, value.mountPos.epoch(), pars_d);
|
||||
if (ep_err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
MccSerializerBase::addElemDelimiter(output, pars_h);
|
||||
|
||||
|
||||
// status (it must be formattable, see mcc_concepts.h)
|
||||
|
||||
auto st_err =
|
||||
MccSerializer<decltype(value.hwState.movementState)>{}(output, value.hwState.movementState, pars_d);
|
||||
if (st_err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static_assert(mcc_serializer_c<MccSerializer<MccAngle>>, "!!!");
|
||||
|
||||
} // namespace mcc::impl
|
||||
1178
mcc_serializer.h
1178
mcc_serializer.h
File diff suppressed because it is too large
Load Diff
910
mcc_serializer.h.old
Normal file
910
mcc_serializer.h.old
Normal file
@@ -0,0 +1,910 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF SERIALIZER CLASSES *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <atomic>
|
||||
#include <concepts>
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_constants.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_error.h"
|
||||
#include "mcc_traits.h"
|
||||
#include "mcc_utils.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccSerializerErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_UNDERLYING_SERIALIZER,
|
||||
ERROR_INVALID_EPOCH,
|
||||
ERROR_COORD_TRANSFORM
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccSerializerErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
// error category
|
||||
struct MccSerializerCategory : public std::error_category {
|
||||
MccSerializerCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "MCC-SERIALIZER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
MccSerializerErrorCode err = static_cast<MccSerializerErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccSerializerErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER:
|
||||
return "error returned by underlying serializer";
|
||||
case MccSerializerErrorCode::ERROR_INVALID_EPOCH:
|
||||
return "invalid coordinate epoch";
|
||||
case MccSerializerErrorCode::ERROR_COORD_TRANSFORM:
|
||||
return "coordinates transformation error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccSerializerCategory& get()
|
||||
{
|
||||
static const MccSerializerCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccSerializerErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccSerializerCategory::get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_serializer_interface_t {
|
||||
virtual ~mcc_serializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
|
||||
template <std::derived_from<mcc_serializer_interface_t> SelfT,
|
||||
traits::mcc_output_char_range R,
|
||||
typename ValueT,
|
||||
typename FmtT>
|
||||
requires(std::same_as<std::format_string<ValueT>, FmtT> || std::same_as<std::string_view, FmtT>)
|
||||
RetT operator()(this SelfT&& self, R& output, ValueT const& value, FmtT fmt)
|
||||
{
|
||||
return std::forward<SelfT>(self)(output, value, std::move(fmt));
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_serializer_interface_t() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_serializer_c = std::derived_from<T, mcc_serializer_interface_t<typename T::error_t>>;
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
struct MccSerializerBase : mcc_serializer_interface_t<impl::MccError>, utils::mcc_elem_sequence_with_delim_t {
|
||||
using typename mcc_serializer_interface_t<impl::MccError>::error_t;
|
||||
|
||||
virtual ~MccSerializerBase() = default;
|
||||
|
||||
protected:
|
||||
MccSerializerBase() = default;
|
||||
|
||||
template <typename VT, typename R>
|
||||
requires(std::ranges::input_range<R> && std::same_as<VT, std::ranges::range_value_t<R>>)
|
||||
error_t serializingRange(mcc_serializer_c auto& sr,
|
||||
R const& r,
|
||||
traits::mcc_output_char_range auto& output,
|
||||
auto fmt) const
|
||||
{
|
||||
size_t i = 0, N = std::ranges::size(r);
|
||||
|
||||
for (auto const& el : r) {
|
||||
auto err = sr(output, el, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
if (++i < N) {
|
||||
std::format_to(std::back_inserter(output), "{}", _seqDelimiter);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
/* fallback template */
|
||||
template <typename VT>
|
||||
class MccSerializer : public details::MccSerializerBase
|
||||
// class MccSerializer : public mcc_serializer_interface_t<impl::MccError>
|
||||
{
|
||||
public:
|
||||
// default delimiter
|
||||
static constexpr std::string_view defaultRangeDelimiter{","};
|
||||
|
||||
// typedef impl::MccError error_t;
|
||||
|
||||
MccSerializer() = default;
|
||||
|
||||
~MccSerializer() = default;
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::formattable<VT, char>) {
|
||||
if constexpr (std::is_null_pointer_v<FmtT>) {
|
||||
std::format_to(std::back_inserter(output), "{}", value);
|
||||
} else if constexpr (traits::mcc_input_char_range<FmtT>) {
|
||||
std::string_view sfmt{fmt.begin(), fmt.end()};
|
||||
std::vformat_to(std::back_inserter(output), sfmt, std::make_format_args(value));
|
||||
} else if constexpr (std::same_as<std::format_string<VT>, FmtT>) {
|
||||
std::format_to(std::back_inserter(output), std::move(fmt), value);
|
||||
} else {
|
||||
static_assert(false, "INVALID FORMAT STRING TYPE!!!");
|
||||
}
|
||||
} else if constexpr (std::convertible_to<VT, std::string>) {
|
||||
auto err = MccSerializer<std::string>{}(output, static_cast<std::string>(value), std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
|
||||
// special range (character sequence)
|
||||
if constexpr (std::same_as<value_t, char>) {
|
||||
std::string str;
|
||||
std::ranges::copy(value, std::back_inserter(str));
|
||||
|
||||
auto err = MccSerializer<std::string>{}(output, str, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
} else {
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(traits::mcc_systime_c<VT> ||
|
||||
(std::ranges::input_range<VT> && traits::mcc_systime_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public details::MccSerializerBase
|
||||
{
|
||||
public:
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar
|
||||
if constexpr (std::is_null_pointer_v<FmtT>) {
|
||||
std::format_to(std::back_inserter(output), "{:%FT%T}", value);
|
||||
} else if constexpr (traits::mcc_input_char_range<FmtT>) {
|
||||
std::string_view sfmt{fmt.begin(), fmt.end()};
|
||||
if (sfmt == "{}") {
|
||||
sfmt = "{:%FT%T}";
|
||||
}
|
||||
std::vformat_to(std::back_inserter(output), sfmt, std::make_format_args(value));
|
||||
} else if constexpr (std::same_as<std::format_string<VT>, FmtT>) {
|
||||
std::string_view sfmt{fmt.get().begin(), fmt.get().end()};
|
||||
if (sfmt == "{}") {
|
||||
std::format_to(std::back_inserter(output), "{:%FT%T}", value);
|
||||
} else {
|
||||
std::format_to(std::back_inserter(output), std::move(fmt), value);
|
||||
}
|
||||
} else {
|
||||
static_assert(false, "INVALID FORMAT STRING TYPE!!!");
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> &&
|
||||
(mcc_angle_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_angle_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>)))
|
||||
class MccSerializer<VT> : public virtual details::MccSerializerBase
|
||||
// class MccSerializer<VT> : public mcc_serializer_interface_t<impl::MccError>
|
||||
{
|
||||
public:
|
||||
enum SerializedCoordFormat {
|
||||
CFMT_DEGREES, // floating-point representation in degrees
|
||||
CFMT_SGM_HOURS, // sexagesimal representation: HH:MM:SS.SSSSSS (hours:minutes:seconds)
|
||||
CFMT_SGM_DEGS // sexagesimal representation: DD:MM:SS.SSSSS (degrees:arcmins::arcsecs)
|
||||
};
|
||||
|
||||
struct SexagesimalCoordPrec {
|
||||
uint8_t hour_prec = 2; // number of decimal places in hour seconds
|
||||
uint8_t deg_prec = 1; // number of decimal places in arcseconds
|
||||
};
|
||||
|
||||
// typedef impl::MccError error_t;
|
||||
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
void setCoordFormat(SerializedCoordFormat format)
|
||||
{
|
||||
_coordFormat = format;
|
||||
}
|
||||
|
||||
SerializedCoordFormat getCoordFormat() const
|
||||
{
|
||||
return _coordFormat;
|
||||
}
|
||||
|
||||
|
||||
void setCoordPrec(SexagesimalCoordPrec prec)
|
||||
{
|
||||
_coordPrec = std::move(prec);
|
||||
}
|
||||
|
||||
SexagesimalCoordPrec getCoordPrec() const
|
||||
{
|
||||
return _coordPrec;
|
||||
}
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
sr.setCoordFormat(_coordFormat);
|
||||
sr.setCoordPrec(_coordPrec);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar
|
||||
double v = (double)value; // radians
|
||||
std::string sgm;
|
||||
|
||||
switch (_coordFormat) {
|
||||
case MccSerializer::CFMT_DEGREES:
|
||||
v *= 180.0 / std::numbers::pi;
|
||||
return MccSerializer<double>{}(output, v, std::move(fmt));
|
||||
case MccSerializer::CFMT_SGM_HOURS:
|
||||
sgm = utils::rad2sxg(v, true, _coordPrec.load().hour_prec);
|
||||
break;
|
||||
case MccSerializer::CFMT_SGM_DEGS:
|
||||
sgm = utils::rad2sxg(v, false, _coordPrec.load().deg_prec);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
auto err = MccSerializer<std::string>{}(output, sgm, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
// std::atomic<SerializedCoordFormat> _coordFormat{MccSerializer::CFMT_DEGREES};
|
||||
std::atomic<SerializedCoordFormat> _coordFormat{MccSerializer::CFMT_SGM_DEGS};
|
||||
std::atomic<SexagesimalCoordPrec> _coordPrec{SexagesimalCoordPrec{.hour_prec = 2, .deg_prec = 1}};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_epoch_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_coord_epoch_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public virtual details::MccSerializerBase
|
||||
{
|
||||
public:
|
||||
enum TimePointFormat { TP_FORMAT_DATE, TP_FORMAT_MJD, TP_FORMAT_JEPOCH };
|
||||
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
void setTimePointFormat(TimePointFormat format)
|
||||
{
|
||||
_tpFormat = format;
|
||||
}
|
||||
|
||||
TimePointFormat getTimePointFormat() const
|
||||
{
|
||||
return _tpFormat;
|
||||
}
|
||||
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
sr.setTimePointFormat(_tpFormat);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else {
|
||||
switch (_tpFormat) {
|
||||
case TP_FORMAT_DATE: {
|
||||
auto utc = value.UTC();
|
||||
auto err = MccSerializer<std::remove_cvref_t<decltype(utc)>>{}(output, utc, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} break;
|
||||
case TP_FORMAT_MJD: {
|
||||
double mjd = value.MJD();
|
||||
auto err = MccSerializer<double>{}(output, mjd, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
} break;
|
||||
case TP_FORMAT_JEPOCH: {
|
||||
auto jepoch = value.JEpoch();
|
||||
auto err = MccSerializer<std::remove_cvref_t<decltype(jepoch)>>{}(output, jepoch, std::move(fmt));
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::atomic<TimePointFormat> _tpFormat{TP_FORMAT_DATE};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_pair_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_coord_pair_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>,
|
||||
public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccAngle>>,
|
||||
MccSerializer<MccAngle>>
|
||||
// class MccSerializer<VT> : public mcc_serializer_interface_t<MccError>
|
||||
{
|
||||
protected:
|
||||
typedef std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>
|
||||
base_ser_epoch_t;
|
||||
|
||||
typedef std::
|
||||
conditional_t<std::ranges::input_range<VT>, MccSerializer<std::vector<MccAngle>>, MccSerializer<MccAngle>>
|
||||
base_ser_angle_t;
|
||||
|
||||
public:
|
||||
using typename details::MccSerializerBase::error_t;
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
sr.setTimePointFormat(this->_tpFormat);
|
||||
sr.setCoordFormat(this->_coordFormat);
|
||||
sr.setCoordPrec(this->_coordPrec);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar: format X[elem-delimiter]Y[elem-delimiter]epoch[elem-delimiter]pair-kind
|
||||
|
||||
// WARNING: still ignore format string!!!
|
||||
|
||||
error_t err;
|
||||
|
||||
// format to sexagesimal form according to celestial coordinate type (general XY-type is skipped)
|
||||
if (this->_coordFormat != base_ser_angle_t::CFMT_DEGREES) {
|
||||
auto prev_format = this->_coordFormat.load();
|
||||
|
||||
if constexpr (VT::pairKind == MccCoordPairKind::COORDS_KIND_AZZD ||
|
||||
VT::pairKind == MccCoordPairKind::COORDS_KIND_AZALT) { // azimuth is in degrees
|
||||
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.x()});
|
||||
} else { // RA or HA are in hours
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.x()});
|
||||
}
|
||||
|
||||
this->setCoordFormat(prev_format); // restore previous value
|
||||
} else { // here all angles in deciamal degrees
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.x()});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
// format to sexagesimal form according to celestial coordinate type (general XY-type is skipped)
|
||||
// Y-coordinate of the celestial point is always in degrees
|
||||
if (this->_coordFormat != base_ser_angle_t::CFMT_DEGREES) {
|
||||
auto prev_format = this->_coordFormat.load();
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.y()});
|
||||
|
||||
this->setCoordFormat(prev_format); // restore previous value
|
||||
} else { // here all angles in deciamal degrees
|
||||
err = base_ser_angle_t::operator()(output, MccAngle{(double)value.y()});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
auto ep = value.epoch();
|
||||
if constexpr (std::convertible_to<decltype(ep), MccCelestialCoordEpoch>) {
|
||||
auto err_e = base_ser_epoch_t::operator()(output, MccCelestialCoordEpoch{ep});
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
} else {
|
||||
MccCelestialCoordEpoch ep1;
|
||||
bool ok = ep1.fromMJD(ep.MJD());
|
||||
if (!ok) {
|
||||
return MccSerializerErrorCode::ERROR_INVALID_EPOCH;
|
||||
}
|
||||
|
||||
auto err_e = (*this)(output, ep1);
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
auto err_s = MccSerializer<std::string_view>{}(output, MccCoordPairKindToStr(VT::pairKind));
|
||||
if (err_s) {
|
||||
return mcc_deduced_err(err_s, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_skypoint_c<VT> ||
|
||||
(std::ranges::input_range<VT> && mcc_skypoint_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccSerializer<VT> : public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>,
|
||||
public std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccAngle>>,
|
||||
MccSerializer<MccAngle>>
|
||||
{
|
||||
protected:
|
||||
typedef std::conditional_t<std::ranges::input_range<VT>,
|
||||
MccSerializer<std::vector<MccCelestialCoordEpoch>>,
|
||||
MccSerializer<MccCelestialCoordEpoch>>
|
||||
base_ser_epoch_t;
|
||||
|
||||
typedef std::
|
||||
conditional_t<std::ranges::input_range<VT>, MccSerializer<std::vector<MccAngle>>, MccSerializer<MccAngle>>
|
||||
base_ser_angle_t;
|
||||
|
||||
public:
|
||||
using typename details::MccSerializerBase::error_t;
|
||||
|
||||
enum SkyPointFormat {
|
||||
SKYPOINT_FORMAT_FULL, // return RA_ICRS, DEC_ICRS, RA_APP, DEC_APP, RA_OBS, DEC_OBS, AZ, ZD, HA_APP,
|
||||
// TIME-POINT
|
||||
SKYPOINT_FORMAT_OBS, // return observed coordinates: RA_OBS, DEC_OBS, AZ, ZD, HA_OBS, TIME-POINT
|
||||
SKYPOINT_FORMAT_APP, // return apparent (in vacuo) coordinates: RA_APP, DEC_APP, HA_APP, TIME-POINT
|
||||
SKYPOINT_FORMAT_PAIR // return current stored coordinate pair: X, Y, TIME-POINT, PAIR-KIND
|
||||
};
|
||||
|
||||
virtual ~MccSerializer() = default;
|
||||
|
||||
void setSkyPointFormat(SkyPointFormat format)
|
||||
{
|
||||
_skptFormat = format;
|
||||
}
|
||||
|
||||
SkyPointFormat getSkyPointFormat() const
|
||||
{
|
||||
return _skptFormat;
|
||||
}
|
||||
|
||||
template <typename FmtT = std::nullptr_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output, VT const& value, FmtT fmt = nullptr)
|
||||
{
|
||||
if constexpr (std::ranges::input_range<VT>) {
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccSerializer<value_t> sr;
|
||||
|
||||
sr.setTimePointFormat(this->_tpFormat);
|
||||
sr.setCoordFormat(this->_coordFormat);
|
||||
sr.setCoordPrec(this->_coordPrec);
|
||||
|
||||
return serializingRange<value_t>(sr, value, output, std::move(fmt));
|
||||
} else { // scalar
|
||||
|
||||
auto serialize_pair_func = [&output, this]<typename PT>(PT const& pt) -> error_t {
|
||||
MccSerializer<PT> pt_sr;
|
||||
|
||||
pt_sr.setTimePointFormat(this->_tpFormat);
|
||||
pt_sr.setCoordFormat(this->_coordFormat);
|
||||
pt_sr.setCoordPrec(this->_coordPrec);
|
||||
|
||||
auto err = pt_sr(output, pt);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
};
|
||||
|
||||
// WARNING: still ignore format string!!!
|
||||
|
||||
auto skpt_fmt = _skptFormat.load();
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_PAIR) {
|
||||
switch (value.pairKind()) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
return serialize_pair_func(value.operator MccSkyRADEC_ICRS());
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
||||
return serialize_pair_func(value.operator MccSkyRADEC_APP());
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS:
|
||||
return serialize_pair_func(value.operator MccSkyRADEC_OBS());
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
||||
return serialize_pair_func(value.operator MccSkyHADEC_APP());
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS:
|
||||
return serialize_pair_func(value.operator MccSkyHADEC_OBS());
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD:
|
||||
return serialize_pair_func(value.operator MccSkyAZZD());
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT:
|
||||
return serialize_pair_func(value.operator MccSkyAZALT());
|
||||
case MccCoordPairKind::COORDS_KIND_XY:
|
||||
return serialize_pair_func(value.operator MccGenXY());
|
||||
default:
|
||||
return serialize_pair_func(value.operator MccGenXY()); // ???????!!!!!!!!!!!
|
||||
}
|
||||
} else {
|
||||
MccSkyRADEC_ICRS radec_icrs;
|
||||
MccSkyRADEC_OBS radec_obs;
|
||||
MccSkyHADEC_OBS hadec_obs;
|
||||
MccSkyRADEC_APP radec_app;
|
||||
MccSkyHADEC_APP hadec_app;
|
||||
MccSkyAZZD azzd;
|
||||
// MccGenXY xy;
|
||||
|
||||
if (value.pairKind() == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
||||
auto ep_now = MccCelestialCoordEpoch::now();
|
||||
radec_obs.setEpoch(ep_now);
|
||||
radec_app.setEpoch(ep_now);
|
||||
hadec_obs.setEpoch(ep_now);
|
||||
hadec_app.setEpoch(ep_now);
|
||||
azzd.setEpoch(ep_now);
|
||||
} else {
|
||||
auto ep = value.epoch();
|
||||
radec_obs.setEpoch(ep);
|
||||
radec_app.setEpoch(ep);
|
||||
hadec_obs.setEpoch(ep);
|
||||
hadec_app.setEpoch(ep);
|
||||
azzd.setEpoch(ep);
|
||||
}
|
||||
|
||||
auto prev_format = this->_coordFormat.load();
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_FULL) { // RA_ICRS, DEC_ICRS, RA_APP, DEC_APP
|
||||
auto err = value.to(radec_icrs, radec_app);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// RA_ICRS is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_icrs.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_ICRS is in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_icrs.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
// RA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_APP is in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_OBS || skpt_fmt == SKYPOINT_FORMAT_FULL) { // RA_OBS, DEC_OBS, AZ, ZD
|
||||
auto err = value.to(radec_obs, azzd);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// RA_OBS is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_obs.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_OBS, AZ and ZD are in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_obs.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)azzd.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)azzd.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_FULL) { // HA_APP
|
||||
auto err = value.to(hadec_app);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// HA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)hadec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_OBS) { // HA_OBS
|
||||
auto err = value.to(hadec_obs);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// HA_OBS is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)hadec_obs.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
|
||||
if (skpt_fmt == SKYPOINT_FORMAT_APP) { // RA_APP, DEC_APP, HA_APP
|
||||
auto err = value.to(radec_app, hadec_app);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_COORD_TRANSFORM);
|
||||
}
|
||||
|
||||
// RA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
auto err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
|
||||
// DEC_APP is in sexagesimal degrees
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_DEGS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)radec_app.y()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
|
||||
// HA_APP is in sexagesimal hours
|
||||
if (prev_format != base_ser_angle_t::CFMT_DEGREES) {
|
||||
this->setCoordFormat(base_ser_angle_t::CFMT_SGM_HOURS);
|
||||
}
|
||||
|
||||
err_ang = base_ser_angle_t::operator()(output, MccAngle{(double)hadec_app.x()});
|
||||
if (err_ang) {
|
||||
return mcc_deduced_err(err_ang, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", this->_elementDelimiter);
|
||||
}
|
||||
|
||||
this->setCoordFormat(prev_format); // restore previous value
|
||||
|
||||
|
||||
// epoch of app/obs coordinates
|
||||
auto ep = value.epoch();
|
||||
if constexpr (std::convertible_to<decltype(ep), MccCelestialCoordEpoch>) {
|
||||
auto err_e = base_ser_epoch_t::operator()(output, MccCelestialCoordEpoch{ep});
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
} else {
|
||||
MccCelestialCoordEpoch ep1;
|
||||
bool ok = ep1.fromMJD(ep.MJD());
|
||||
if (!ok) {
|
||||
return MccSerializerErrorCode::ERROR_INVALID_EPOCH;
|
||||
}
|
||||
|
||||
auto err_e = (*this)(output, ep1);
|
||||
if (err_e) {
|
||||
return err_e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::atomic<SkyPointFormat> _skptFormat{SKYPOINT_FORMAT_FULL};
|
||||
};
|
||||
|
||||
|
||||
|
||||
static_assert(mcc_serializer_c<MccSerializer<float>>, "!!!");
|
||||
|
||||
static_assert(mcc_serializer_c<MccSerializer<impl::MccAngle>>, "!!!");
|
||||
|
||||
static_assert(std::atomic<MccSerializer<impl::MccAngle>::SerializedCoordFormat>::is_always_lock_free, "!!!");
|
||||
static_assert(std::atomic<MccSerializer<impl::MccAngle>::SexagesimalCoordPrec>::is_always_lock_free, "!!!");
|
||||
|
||||
static_assert(std::formattable<impl::MccAngle, char>, "!!!");
|
||||
|
||||
void f()
|
||||
{
|
||||
MccSerializer<impl::MccAngle> s;
|
||||
|
||||
std::string str;
|
||||
s(str, impl::MccAngleALT{1.1});
|
||||
}
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <iostream>
|
||||
|
||||
// #include <mcc_ccte_erfa.h>
|
||||
#include <mcc_coordinate.h>
|
||||
// #include <mcc_coordinate.h>
|
||||
#include <mcc_deserializer.h>
|
||||
#include <mcc_serializer.h>
|
||||
|
||||
@@ -26,10 +26,13 @@ void serialize(VT const& value)
|
||||
{
|
||||
MccSerializer<VT> ser;
|
||||
std::string s;
|
||||
mcc_serialization_params_t pars{};
|
||||
pars.norm_sxgm = true;
|
||||
pars.coordpair_format = mcc::MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG;
|
||||
|
||||
auto err = ser(s, value);
|
||||
auto err = ser(s, value, pars);
|
||||
if (err) {
|
||||
std::cout << "SERIALIZING ERR: " << err << "\n";
|
||||
std::cout << "SERIALIZING ERR: " << err.message() << "\n";
|
||||
} else {
|
||||
std::cout << "SERIALIZED: " << s << "\n";
|
||||
}
|
||||
@@ -136,6 +139,9 @@ int main()
|
||||
std::cout << "\tfor 'double' type: ";
|
||||
serialize(v);
|
||||
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(icrs);
|
||||
|
||||
std::cout << "\tfor 'coord pair' type: ";
|
||||
serialize(radec_obs);
|
||||
|
||||
|
||||
@@ -61,6 +61,17 @@ struct hw_t {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::formatter<hw_t::hardware_movement_state_t, char>
|
||||
: std::formatter<std::underlying_type_t<hw_t::hardware_movement_state_t>, char> {
|
||||
auto format(hw_t::hardware_movement_state_t e, auto& ctx) const
|
||||
{
|
||||
return formatter<std::underlying_type_t<hw_t::hardware_movement_state_t>>::format(
|
||||
std::underlying_type_t<hw_t::hardware_movement_state_t>(e), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static_assert(mcc::mcc_hardware_c<hw_t>, "!!!!!");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user