|
|
|
|
@@ -492,8 +492,20 @@ static_assert(mcc_netmsg_valid_keys_c<MccNetMessageValidKeywords>, "");
|
|
|
|
|
template <mcc_netmsg_valid_keys_c BASE_T, traits::mcc_char_range BYTEREPR_T>
|
|
|
|
|
class MccNetMessage
|
|
|
|
|
{
|
|
|
|
|
static inline utils::MccSimpleDeserializer defaultDeserilizer{MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ};
|
|
|
|
|
public:
|
|
|
|
|
/* helper types to format serialized celestial coordinates */
|
|
|
|
|
/* it can be used as inputs in "construct" method or corresponded constructor */
|
|
|
|
|
|
|
|
|
|
// format of output (serialized) coordinates
|
|
|
|
|
enum MccNetMessageCoordFormat { CFMT_DEGREES, CFMT_SGM };
|
|
|
|
|
|
|
|
|
|
// precision of sexagesimal coordinates (number of decimal places in seconds/arcseconds)
|
|
|
|
|
struct MccNetMessageCoordPrec {
|
|
|
|
|
uint8_t hour_prec = 2;
|
|
|
|
|
uint8_t deg_prec = 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
class DefaultDeserializer : protected utils::MccSimpleDeserializer
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
@@ -512,13 +524,13 @@ class MccNetMessage
|
|
|
|
|
return ec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vs.size() < 2) {
|
|
|
|
|
if (vs.size() < 2) { // al least a pair of coordinates must be given
|
|
|
|
|
return std::make_error_code(std::errc::invalid_argument);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MccCelestialPoint pt{.pair_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
|
|
|
|
|
|
|
|
|
if (vs.size() > 2) {
|
|
|
|
|
if (vs.size() > 2) { // pair of coordinates and the pair kind
|
|
|
|
|
pt.pair_kind = MccCoordStrToPairKind(vs[2]);
|
|
|
|
|
if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_GENERIC) {
|
|
|
|
|
return std::make_error_code(std::errc::invalid_argument);
|
|
|
|
|
@@ -532,17 +544,25 @@ class MccNetMessage
|
|
|
|
|
std::chrono::hours(11) + std::chrono::minutes(58) + std::chrono::milliseconds(55816);
|
|
|
|
|
mcc_tp2tp(tp, pt.time_point);
|
|
|
|
|
} else {
|
|
|
|
|
if (vs.size() > 3) {
|
|
|
|
|
std::chrono::sys_time<std::chrono::system_clock::duration> tp;
|
|
|
|
|
if (vs.size() > 3) { // coordinates epoch is given
|
|
|
|
|
// std::chrono::sys_time<std::chrono::system_clock::duration> tp;
|
|
|
|
|
|
|
|
|
|
std::istringstream iss(std::string{utils::trimSpaces(vs[3])});
|
|
|
|
|
// std::istringstream iss(std::string{utils::trimSpaces(vs[3])});
|
|
|
|
|
|
|
|
|
|
std::chrono::from_stream(iss, "%FT%T", tp);
|
|
|
|
|
if (iss.fail()) {
|
|
|
|
|
// std::chrono::from_stream(iss, "%FT%T", tp);
|
|
|
|
|
// if (iss.fail()) {
|
|
|
|
|
// return std::make_error_code(std::errc::invalid_argument);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// mcc_tp2tp(tp, pt.time_point);
|
|
|
|
|
|
|
|
|
|
MccCelestialCoordEpoch cep;
|
|
|
|
|
// bool ok = cep.fromCharRange(utils::trimSpaces(vs[3]));
|
|
|
|
|
bool ok = cep.fromCharRange(vs[3]);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
return std::make_error_code(std::errc::invalid_argument);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mcc_tp2tp(tp, pt.time_point);
|
|
|
|
|
mcc_tp2tp(cep.UTC(), pt.time_point);
|
|
|
|
|
} else { // no time point - use NOW
|
|
|
|
|
mcc_tp2tp(std::chrono::system_clock::now(), pt.time_point);
|
|
|
|
|
}
|
|
|
|
|
@@ -574,7 +594,7 @@ class MccNetMessage
|
|
|
|
|
pt.X = MccAngle(ang1.value(), mcc::MccDegreeTag{});
|
|
|
|
|
pt.Y = MccAngle(ang2.value(), mcc::MccDegreeTag{});
|
|
|
|
|
|
|
|
|
|
mcc_copy_celestial_point(pt, value);
|
|
|
|
|
mcc_copy_celestial_point(pt, &value);
|
|
|
|
|
} else {
|
|
|
|
|
return base_t::operator()(std::forward<IR>(bytes), value);
|
|
|
|
|
}
|
|
|
|
|
@@ -583,48 +603,88 @@ class MccNetMessage
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// helper method to convert celestial point to char range
|
|
|
|
|
// (actually, to range of strings)
|
|
|
|
|
template <traits::mcc_output_char_range R>
|
|
|
|
|
static R celestialPointToString(mcc_celestial_point_c auto const& pt,
|
|
|
|
|
bool degrees = false,
|
|
|
|
|
std::pair<int, int> prec = {2, 1})
|
|
|
|
|
{
|
|
|
|
|
R res;
|
|
|
|
|
|
|
|
|
|
if (degrees) {
|
|
|
|
|
std::format_to(std::back_inserter(res), "{}{}{}", MccAngle(pt.X).degrees(),
|
|
|
|
|
MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, MccAngle(pt.Y).degrees());
|
|
|
|
|
class DefaultSerializer
|
|
|
|
|
{
|
|
|
|
|
MccNetMessageCoordFormat _currentCoordFormat = MccNetMessage::CFMT_SGM;
|
|
|
|
|
MccNetMessageCoordPrec _currentCoordPrec{2, 1};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
void setCoordFormat(MccNetMessageCoordFormat fmt)
|
|
|
|
|
{
|
|
|
|
|
_currentCoordFormat = fmt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setCoordPrec(MccNetMessageCoordPrec prec)
|
|
|
|
|
{
|
|
|
|
|
_currentCoordPrec = prec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T, traits::mcc_output_char_range OR>
|
|
|
|
|
void operator()(const T& value, OR& bytes)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::is_arithmetic_v<T>) {
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{}", value);
|
|
|
|
|
} else if constexpr (std::convertible_to<T, std::string>) {
|
|
|
|
|
std::ranges::copy(static_cast<std::string>(value), std::back_inserter(bytes));
|
|
|
|
|
} else if constexpr (std::constructible_from<std::string, T>) {
|
|
|
|
|
std::ranges::copy(std::string(value), std::back_inserter(bytes));
|
|
|
|
|
} else if constexpr (traits::mcc_char_range<T>) {
|
|
|
|
|
std::ranges::copy(std::string(value.begin(), value.end()), std::back_inserter(bytes));
|
|
|
|
|
} else if constexpr (std::same_as<T, MccCoordPairKind>) {
|
|
|
|
|
std::ranges::copy(mcc_pairkind2str(value), std::back_inserter(bytes));
|
|
|
|
|
} else if constexpr (traits::mcc_time_duration_c<T>) {
|
|
|
|
|
(*this)(value.count(), bytes);
|
|
|
|
|
} else if constexpr (mcc_celestial_point_c<T>) {
|
|
|
|
|
if (_currentCoordFormat == MccNetMessage::CFMT_DEGREES) {
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{}{}{}", MccAngle(value.X).degrees(),
|
|
|
|
|
MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, MccAngle(value.Y).degrees());
|
|
|
|
|
} else {
|
|
|
|
|
switch (pt.pair_kind) {
|
|
|
|
|
switch (value.pair_kind) {
|
|
|
|
|
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
|
|
|
|
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
|
|
|
|
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
|
|
|
|
std::format_to(std::back_inserter(res), "{}{}", MccAngle(pt.X).sexagesimal(true, prec.first),
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{}{}",
|
|
|
|
|
MccAngle(value.X).sexagesimal(true, _currentCoordPrec.hour_prec),
|
|
|
|
|
MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
std::format_to(std::back_inserter(res), "{}{}", MccAngle(pt.X).sexagesimal(false, prec.second),
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{}{}",
|
|
|
|
|
MccAngle(value.X).sexagesimal(false, _currentCoordPrec.deg_prec),
|
|
|
|
|
MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::format_to(std::back_inserter(res), "{}", MccAngle(pt.Y).sexagesimal(false, prec.second));
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{}",
|
|
|
|
|
MccAngle(value.Y).sexagesimal(false, _currentCoordPrec.deg_prec));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::format_to(std::back_inserter(res), "{0:}{1:}{2:}{3:%F}T{3:%T}", MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ,
|
|
|
|
|
MccCoordPairKindToStr(pt.pair_kind), MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, pt.time_point);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{0:}{1:}{2:}{3:%F}T{3:%T}",
|
|
|
|
|
MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, MccCoordPairKindToStr(value.pair_kind),
|
|
|
|
|
MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, value.time_point);
|
|
|
|
|
} else if constexpr (std::ranges::range<T>) {
|
|
|
|
|
auto sz = std::ranges::size(value);
|
|
|
|
|
if (sz == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string celestialPointToString(mcc_celestial_point_c auto const& pt,
|
|
|
|
|
bool degrees = false,
|
|
|
|
|
std::pair<int, int> prec = {2, 1})
|
|
|
|
|
{
|
|
|
|
|
return celestialPointToString<std::string>(pt, degrees, prec);
|
|
|
|
|
}
|
|
|
|
|
(*this)(*value.begin(), bytes); // the first element
|
|
|
|
|
|
|
|
|
|
if (sz > 1) {
|
|
|
|
|
for (auto const& el : value | std::views::drop(1)) {
|
|
|
|
|
std::ranges::copy(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, std::back_inserter(bytes));
|
|
|
|
|
(*this)(el, bytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if constexpr (std::formattable<T, char>) {
|
|
|
|
|
std::format_to(std::back_inserter(bytes), "{}", value);
|
|
|
|
|
} else {
|
|
|
|
|
static_assert(false, "UNSUPPORTED TYPE!!!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
typedef BASE_T valid_keys_t;
|
|
|
|
|
typedef BYTEREPR_T byte_repr_t;
|
|
|
|
|
|
|
|
|
|
@@ -768,81 +828,10 @@ public:
|
|
|
|
|
template <typename T>
|
|
|
|
|
std::expected<T, std::error_code> paramValue(size_t idx)
|
|
|
|
|
{
|
|
|
|
|
return paramValue<T>(idx, defaultDeserilizer);
|
|
|
|
|
return paramValue<T>(idx, _defaultDeserilizer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// template <mcc_celestial_point_c CT>
|
|
|
|
|
// std::expected<CT, std::error_code> paramCelestialPoint(
|
|
|
|
|
// size_t from_idx,
|
|
|
|
|
// MccCoordPairKind default_kind = MccCoordPairKind::COORDS_KIND_RADEC_ICRS)
|
|
|
|
|
// {
|
|
|
|
|
// if (_params.size() < (from_idx + 2)) {
|
|
|
|
|
// return std::unexpected(std::make_error_code(std::errc::message_size));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// MccCelestialPoint pt{.pair_kind = default_kind};
|
|
|
|
|
|
|
|
|
|
// if (_params.size() > (from_idx + 2)) {
|
|
|
|
|
// pt.pair_kind = MccCoordStrToPairKind(_params[from_idx + 2]);
|
|
|
|
|
// if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_GENERIC) {
|
|
|
|
|
// return std::unexpected(std::make_error_code(std::errc::invalid_argument));
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (pt.pair_kind == MccCoordPairKind::COORDS_KIND_RADEC_ICRS) {
|
|
|
|
|
// // J2000.0: 11:58:55.816 1 January 2000 UTC
|
|
|
|
|
// auto tp = std::chrono::sys_days(std::chrono::year_month_day(std::chrono::January / std::chrono::day(1) /
|
|
|
|
|
// std::chrono::year(2000))) +
|
|
|
|
|
// std::chrono::hours(11) + std::chrono::minutes(58) + std::chrono::milliseconds(55816);
|
|
|
|
|
// mcc_tp2tp(tp, pt.time_point);
|
|
|
|
|
// } else {
|
|
|
|
|
// if (_params.size() > (from_idx + 3)) {
|
|
|
|
|
// std::chrono::sys_time<std::chrono::system_clock::duration> tp;
|
|
|
|
|
|
|
|
|
|
// std::istringstream iss(std::string{utils::trimSpaces(_params[from_idx + 3])});
|
|
|
|
|
|
|
|
|
|
// std::chrono::from_stream(iss, "%FT%T", tp);
|
|
|
|
|
// if (iss.fail()) {
|
|
|
|
|
// return std::unexpected(std::make_error_code(std::errc::invalid_argument));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// mcc_tp2tp(tp, pt.time_point);
|
|
|
|
|
// } else { // no time point - use NOW
|
|
|
|
|
// mcc_tp2tp(std::chrono::system_clock::now(), pt.time_point);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// std::optional<double> ang1, ang2;
|
|
|
|
|
|
|
|
|
|
// switch (pt.pair_kind) {
|
|
|
|
|
// // if sexagesimal then hours:minutes:seconds form
|
|
|
|
|
// case mcc::MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
|
|
|
|
// case mcc::MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
|
|
|
|
// case mcc::MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
|
|
|
|
// ang1 = utils::parsAngleString(_params[from_idx], true);
|
|
|
|
|
// break;
|
|
|
|
|
// default:
|
|
|
|
|
// // if sexagesimal then degrees:arcminutes:arcseconds form
|
|
|
|
|
// ang1 = utils::parsAngleString(_params[from_idx]);
|
|
|
|
|
// }
|
|
|
|
|
// if (!ang1) {
|
|
|
|
|
// return std::unexpected(std::make_error_code(std::errc::invalid_argument));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// ang2 = utils::parsAngleString(_params[from_idx + 1]);
|
|
|
|
|
// if (!ang2) {
|
|
|
|
|
// return std::unexpected(std::make_error_code(std::errc::invalid_argument));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// pt.X = MccAngle(ang1.value(), mcc::MccDegreeTag{});
|
|
|
|
|
// pt.Y = MccAngle(ang2.value(), mcc::MccDegreeTag{});
|
|
|
|
|
|
|
|
|
|
// return pt;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
template <traits::mcc_view_or_output_char_range R>
|
|
|
|
|
R byteRepr() const
|
|
|
|
|
{
|
|
|
|
|
@@ -965,67 +954,27 @@ protected:
|
|
|
|
|
|
|
|
|
|
BYTEREPR_T _msgBuffer{};
|
|
|
|
|
|
|
|
|
|
inline static DefaultDeserializer _defaultDeserilizer{};
|
|
|
|
|
|
|
|
|
|
DefaultSerializer _defaultSerializer{};
|
|
|
|
|
|
|
|
|
|
template <typename T, typename... Ts>
|
|
|
|
|
void convertFunc(std::vector<size_t>& idx, const T& par, const Ts&... pars)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (std::same_as<T, MccNetMessageCoordFormat>) {
|
|
|
|
|
_defaultSerializer.setCoordFormat(par);
|
|
|
|
|
if constexpr (sizeof...(Ts)) {
|
|
|
|
|
convertFunc(idx, pars...);
|
|
|
|
|
}
|
|
|
|
|
} else if constexpr (std::same_as<T, MccNetMessageCoordPrec>) {
|
|
|
|
|
_defaultSerializer.setCoordPrec(par);
|
|
|
|
|
if constexpr (sizeof...(Ts)) {
|
|
|
|
|
convertFunc(idx, pars...);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end()));
|
|
|
|
|
|
|
|
|
|
// if constexpr (std::is_arithmetic_v<T>) {
|
|
|
|
|
// std::format_to(std::back_inserter(_msgBuffer), "{}", par);
|
|
|
|
|
// } else if constexpr (std::convertible_to<T, std::string>) {
|
|
|
|
|
// std::ranges::copy(static_cast<std::string>(par), std::back_inserter(_msgBuffer));
|
|
|
|
|
// } else if constexpr (std::constructible_from<std::string, T>) {
|
|
|
|
|
// std::ranges::copy(std::string(par), std::back_inserter(_msgBuffer));
|
|
|
|
|
// } else if constexpr (traits::mcc_char_range<T>) {
|
|
|
|
|
// std::ranges::copy(std::string(par.begin(), par.end()), std::back_inserter(_msgBuffer));
|
|
|
|
|
// } else if constexpr (std::same_as<T, MccCoordPairKind>) {
|
|
|
|
|
// std::ranges::copy(mcc_pairkind2str(par), std::back_inserter(_msgBuffer));
|
|
|
|
|
// } else if constexpr (traits::mcc_time_duration_c<T>) {
|
|
|
|
|
// idx.resize(idx.size() - 1);
|
|
|
|
|
// convertFunc(idx, par.count());
|
|
|
|
|
// idx.resize(idx.size() - 1);
|
|
|
|
|
// } else if constexpr (std::formattable<T, char>) {
|
|
|
|
|
// std::format_to(std::back_inserter(_msgBuffer), "{}", par);
|
|
|
|
|
// } else {
|
|
|
|
|
// static_assert(false, "UNSUPPORTED TYPE!!!");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// use the lambda here to enable recursive calling with no special handling of 'idx'
|
|
|
|
|
[](this auto const& self, auto& buff, auto const& p) {
|
|
|
|
|
using p_t = std::decay_t<decltype(p)>;
|
|
|
|
|
|
|
|
|
|
if constexpr (std::is_arithmetic_v<p_t>) {
|
|
|
|
|
std::format_to(std::back_inserter(buff), "{}", p);
|
|
|
|
|
} else if constexpr (std::convertible_to<p_t, std::string>) {
|
|
|
|
|
std::ranges::copy(static_cast<std::string>(p), std::back_inserter(buff));
|
|
|
|
|
} else if constexpr (std::constructible_from<std::string, p_t>) {
|
|
|
|
|
std::ranges::copy(std::string(p), std::back_inserter(buff));
|
|
|
|
|
} else if constexpr (traits::mcc_char_range<p_t>) {
|
|
|
|
|
std::ranges::copy(std::string(p.begin(), p.end()), std::back_inserter(buff));
|
|
|
|
|
} else if constexpr (std::same_as<p_t, MccCoordPairKind>) {
|
|
|
|
|
std::ranges::copy(mcc_pairkind2str(p), std::back_inserter(buff));
|
|
|
|
|
} else if constexpr (traits::mcc_time_duration_c<p_t>) {
|
|
|
|
|
self(buff, p.count());
|
|
|
|
|
} else if constexpr (std::ranges::range<p_t>) {
|
|
|
|
|
auto sz = std::ranges::size(p);
|
|
|
|
|
if (sz == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self(buff, *p.begin()); // the first element
|
|
|
|
|
|
|
|
|
|
if (sz > 1) {
|
|
|
|
|
for (auto const& el : p | std::views::drop(1)) {
|
|
|
|
|
std::ranges::copy(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ, std::back_inserter(buff));
|
|
|
|
|
self(buff, el);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if constexpr (std::formattable<p_t, char>) {
|
|
|
|
|
std::format_to(std::back_inserter(buff), "{}", p);
|
|
|
|
|
} else {
|
|
|
|
|
static_assert(false, "UNSUPPORTED TYPE!!!");
|
|
|
|
|
}
|
|
|
|
|
}(_msgBuffer, par);
|
|
|
|
|
_defaultSerializer(par, _msgBuffer);
|
|
|
|
|
|
|
|
|
|
idx.emplace_back(std::distance(_msgBuffer.begin(), _msgBuffer.end()));
|
|
|
|
|
|
|
|
|
|
@@ -1034,6 +983,7 @@ protected:
|
|
|
|
|
|
|
|
|
|
convertFunc(idx, pars...);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|