...
This commit is contained in:
parent
8b16ac79b8
commit
27dccfe7c0
@ -485,18 +485,24 @@ protected:
|
||||
inline static auto deserializer = []<typename VT>(std::string_view str, VT& value) {
|
||||
std::error_code ec{};
|
||||
|
||||
mcc::utils::MccSimpleDeserializer deser;
|
||||
deser.setRangeDelim(base_t::VALUE_ARRAY_DELIM);
|
||||
|
||||
if constexpr (std::is_arithmetic_v<VT> || mcc::traits::mcc_output_char_range<VT> || std::ranges::range<VT> ||
|
||||
mcc::traits::mcc_time_duration_c<VT>) {
|
||||
ec = base_t::defaultDeserializeFunc(str, value);
|
||||
// ec = base_t::defaultDeserializeFunc(str, value);
|
||||
ec = deser(str, value);
|
||||
} else if constexpr (std::same_as<VT, mcc::MccAngle>) { // assume here all angles are in degrees
|
||||
double vd;
|
||||
ec = base_t::defaultDeserializeFunc(str, vd);
|
||||
// ec = base_t::defaultDeserializeFunc(str, vd);
|
||||
ec = deser(str, value);
|
||||
if (!ec) {
|
||||
value = mcc::MccAngle(vd, mcc::MccDegreeTag{});
|
||||
}
|
||||
} else if constexpr (std::same_as<VT, mcc::MccDefaultPCMType>) {
|
||||
std::string vstr;
|
||||
ec = base_t::defaultDeserializeFunc(str, vstr);
|
||||
// ec = base_t::defaultDeserializeFunc(str, vstr);
|
||||
ec = deser(str, value);
|
||||
|
||||
if (!ec) {
|
||||
auto s = mcc::utils::trimSpaces(vstr);
|
||||
|
||||
@ -38,7 +38,8 @@ namespace mcc::network
|
||||
|
||||
static constexpr std::string_view MCC_COMMPROTO_STOP_SEQ = "\n";
|
||||
static constexpr std::string_view MCC_COMMPROTO_KEYPARAM_DELIM_SEQ = " ";
|
||||
static constexpr std::string_view MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ = " ";
|
||||
static constexpr std::string_view MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ = ";";
|
||||
static constexpr std::string_view MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ = ",";
|
||||
|
||||
|
||||
/* server special keywords */
|
||||
@ -112,7 +113,7 @@ static constexpr std::string_view mcc_pairkind2str(MccCoordPairKind kind)
|
||||
|
||||
/* keywords */
|
||||
|
||||
// NOTE: THE COORDINATES AND TIME-RELATED QUANTITIES CAN BE EXPRESSED IN THE TWO FORMAT:
|
||||
// NOTE: THE COORDINATES AND TIME-RELATED QUANTITIES CAN BE EXPRESSED IN THE TWO FORMATS:
|
||||
// 1) fixed-point real number, e.g. 123.43987537359 or -0.09775
|
||||
// 2) sexagesimal number, e.g. 10:43:43.12 or -123:54:12.435
|
||||
//
|
||||
@ -122,7 +123,7 @@ static constexpr std::string_view mcc_pairkind2str(MccCoordPairKind kind)
|
||||
// IN FORMAT 'HOURS:MINUTES:SECONDS', WHILE DEC/ALT/AZ/ZD COORDINATES MUST
|
||||
// BE EXPRESSED AS '+/-DEGREES:ARCMINUTES:ARCSECONDS'
|
||||
//
|
||||
// USER-ENTERED (FROM NETWORK CLIENTS) COORDINATE PAIR MAY BE PROVIDED IN A MIXED FORM, I.E.,
|
||||
// USER-ENTERED (FROM NETWORK CLIENTS) COORDINATE PAIR CAN BE PROVIDED IN A MIXED FORM, I.E.,
|
||||
// 12.34436658678 10:32:11.432 or
|
||||
// 10:32:11.432 12.34436658678
|
||||
//
|
||||
@ -182,7 +183,7 @@ static constexpr std::string_view MCC_COMMPROTO_KEYWORD_TARGET_STR = "TARGET";
|
||||
// "MOUNT coord-kind", if 'coord-kind' is omitted then coordinates are according to mount type,
|
||||
// i.e., HADEC for equathorial-type mount and AZZD for alt-azimuthal one
|
||||
// e.g.:
|
||||
// "MOUNT RADEC\n" (get mount current apparent RA and DEC mount coordinates)
|
||||
// "MOUNT RADEC\n" (get current apparent RA and DEC mount coordinates)
|
||||
//
|
||||
// server must return "ACK MOUNT X-coord Y-coord XY-kind" or "ERROR INVPAR"
|
||||
// e.g.
|
||||
@ -434,4 +435,160 @@ bool mcc_netmsg_get_cpoint(mcc_netmsg_parse_result_c auto const& parse_res,
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_netmsg_valid_keys_c = requires(T t) {
|
||||
// std::array of valid message keywords
|
||||
[]<size_t N>(std::array<std::string_view, N>) {
|
||||
// to ensure T::NETMSG_VALID_KEYWORDS can be used as compile-time constant
|
||||
static constexpr auto v0 = T::NETMSG_VALID_KEYWORDS[0];
|
||||
return v0;
|
||||
}(T::NETMSG_VALID_KEYWORDS);
|
||||
|
||||
// std::array of valid message keywords hashes
|
||||
[]<size_t N>(std::array<size_t, N>) {
|
||||
// to ensure T::NETMSG_VALID_KEYWORD_HASHES can be used as compile-time constant
|
||||
static constexpr auto v0 = T::NETMSG_VALID_KEYWORD_HASHES[0];
|
||||
return v0;
|
||||
}(T::NETMSG_VALID_KEYWORD_HASHES);
|
||||
|
||||
requires T::NETMSG_VALID_KEYWORDS.size() == T::NETMSG_VALID_KEYWORD_HASHES.size();
|
||||
};
|
||||
|
||||
|
||||
struct MccNetMessageValidKeywords {
|
||||
static constexpr std::array NETMSG_VALID_KEYWORDS = {
|
||||
MCC_COMMPROTO_KEYWORD_SERVER_ACK_STR, MCC_COMMPROTO_KEYWORD_SERVER_ERROR_STR,
|
||||
MCC_COMMPROTO_KEYWORD_COORDFMT_STR, MCC_COMMPROTO_KEYWORD_COORDPREC_STR,
|
||||
MCC_COMMPROTO_KEYWORD_TARGET_STR, MCC_COMMPROTO_KEYWORD_MOUNT_STR,
|
||||
MCC_COMMPROTO_KEYWORD_TELEMETRY_STR, MCC_COMMPROTO_KEYWORD_INIT_STR,
|
||||
MCC_COMMPROTO_KEYWORD_STOP_STR, MCC_COMMPROTO_KEYWORD_SLEW_STR,
|
||||
MCC_COMMPROTO_KEYWORD_MOVE_STR, MCC_COMMPROTO_KEYWORD_TRACK_STR,
|
||||
MCC_COMMPROTO_KEYWORD_STATUS_STR};
|
||||
|
||||
|
||||
// hashes of valid keywords
|
||||
static constexpr std::array NETMSG_VALID_KEYWORD_HASHES = []<size_t... Is>(std::index_sequence<Is...>) {
|
||||
return std::array{mcc::utils::FNV1aHash(NETMSG_VALID_KEYWORDS[Is])...};
|
||||
}(std::make_index_sequence<NETMSG_VALID_KEYWORDS.size()>());
|
||||
|
||||
static std::expected<size_t, std::error_code> isKeywordValid(std::string_view key)
|
||||
{
|
||||
const auto hash = utils::FNV1aHash(key);
|
||||
|
||||
for (auto const& h : NETMSG_VALID_KEYWORD_HASHES) {
|
||||
if (h == hash) {
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
return std::unexpected(std::make_error_code(std::errc::invalid_argument));
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(mcc_netmsg_valid_keys_c<MccNetMessageValidKeywords>, "");
|
||||
|
||||
|
||||
template <mcc_netmsg_valid_keys_c BASE_T, traits::mcc_output_char_range BYTEREPR_T>
|
||||
class MccNetMessage
|
||||
{
|
||||
public:
|
||||
typedef BASE_T valid_keys_t;
|
||||
typedef BYTEREPR_T byte_repr_t;
|
||||
|
||||
template <traits::mcc_input_char_range KT, typename... PTs>
|
||||
MccNetMessage(KT&& key, PTs&&... params)
|
||||
{
|
||||
construct(std::forward<KT>(key), std::forward<PTs>(params)...);
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range KT>
|
||||
bool withKey(const KT& key)
|
||||
{
|
||||
return utils::FNV1aHash(key) == _keywordHash;
|
||||
}
|
||||
|
||||
template <typename T, typename DeserFuncT>
|
||||
std::expected<T, std::error_code> params(DeserFuncT&& deser_func)
|
||||
{
|
||||
T val;
|
||||
|
||||
auto ec = deser_func(_params, val);
|
||||
if (ec) {
|
||||
return std::unexpect(ec);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::expected<T, std::error_code> params()
|
||||
{
|
||||
return params<T>(utils::MccSimpleDeserializer{}.setRangeDelim(MCC_COMMPROTO_RANGEPARAM_DELIM_SEQ));
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range KT, typename... PTs>
|
||||
std::error_code construct(KT&& key, PTs&&... params)
|
||||
{
|
||||
if (!std::ranges::size(key)) {
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
auto r = valid_keys_t::isKeywordValid(key);
|
||||
if (!r) {
|
||||
return r.error();
|
||||
}
|
||||
|
||||
_keywordHash = r.value();
|
||||
|
||||
_msgBuffer = BYTEREPR_T{};
|
||||
|
||||
std::ranges::copy(key, std::back_inserter(_msgBuffer));
|
||||
_keyword = {_msgBuffer.begin(), _msgBuffer.end()};
|
||||
|
||||
_params = std::string_view{};
|
||||
|
||||
if constexpr (sizeof...(PTs)) {
|
||||
std::ranges::copy(MCC_COMMPROTO_KEYPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer));
|
||||
|
||||
[this]<typename T, typename... Ts>(this auto&& self, const T& par, const Ts&... pars) {
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
std::ranges::copy(std::to_string(par), std::back_inserter(_msgBuffer));
|
||||
} 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>) {
|
||||
std::forward<decltype(self)>(self)(par.count());
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED TYPE!!!");
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Ts)) {
|
||||
std::ranges::copy(MCC_COMMPROTO_PARAMPARAM_DELIM_SEQ, std::back_inserter(_msgBuffer));
|
||||
|
||||
std::forward<decltype(self)>(self)(pars...);
|
||||
}
|
||||
}(std::forward<PTs>(params)...);
|
||||
|
||||
_params = {_msgBuffer.begin() + _keyword.size() + MCC_COMMPROTO_KEYPARAM_DELIM_SEQ.size(),
|
||||
_msgBuffer.end()};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t _keywordHash{};
|
||||
std::string_view _keyword{};
|
||||
std::string_view _params{};
|
||||
|
||||
BYTEREPR_T _msgBuffer{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mcc::network
|
||||
|
||||
@ -401,6 +401,94 @@ static constexpr size_t FNV1aHash(std::forward_iterator auto begin, std::sentine
|
||||
}
|
||||
|
||||
|
||||
class MccSimpleDeserializer
|
||||
{
|
||||
public:
|
||||
static constexpr std::string RANGE_DELIM_SEQ = ",";
|
||||
|
||||
template <traits::mcc_input_char_range R>
|
||||
MccSimpleDeserializer& setRangeDelim(R&& r)
|
||||
{
|
||||
if (std::ranges::size(std::forward<R>(r))) {
|
||||
_rangeDelim.clear();
|
||||
std::ranges::copy(std::forward<R>(r), std::back_inserter(_rangeDelim));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <traits::mcc_output_char_range R>
|
||||
R getRangeDelim() const
|
||||
{
|
||||
R r;
|
||||
|
||||
std::ranges::copy(_rangeDelim, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string getRangeDelim() const
|
||||
{
|
||||
return getRangeDelim<std::string>();
|
||||
}
|
||||
|
||||
template <traits::mcc_input_char_range IR, typename VT>
|
||||
std::error_code operator()(IR&& bytes, VT& value)
|
||||
{
|
||||
std::error_code ret{};
|
||||
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(trimSpaces(bytes));
|
||||
if (!v.has_value()) {
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
value = v.value();
|
||||
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
|
||||
VT r;
|
||||
std::ranges::copy(bytes, std::back_inserter(r));
|
||||
value = r;
|
||||
} else if constexpr (std::ranges::range<VT>) {
|
||||
using el_t = std::ranges::range_value_t<VT>;
|
||||
|
||||
if constexpr (std::is_reference_v<el_t> || std::is_const_v<el_t>) { // no reference or constants allowed
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
VT r;
|
||||
el_t elem;
|
||||
|
||||
auto els = std::views::split(bytes, _rangeDelim);
|
||||
|
||||
for (auto const& el : els) {
|
||||
ret = (*this)(std::string_view(el), elem);
|
||||
if (!ret) {
|
||||
std::back_inserter(r) = elem;
|
||||
} else {
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
value = r;
|
||||
} else if constexpr (mcc::traits::mcc_time_duration_c<VT>) {
|
||||
typename VT::rep vd;
|
||||
|
||||
ret = (*this)(trimSpaces(bytes), vd);
|
||||
if (!ret) {
|
||||
value = VT{vd};
|
||||
}
|
||||
} else {
|
||||
ret = std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string _rangeDelim{RANGE_DELIM_SEQ};
|
||||
};
|
||||
|
||||
|
||||
/* key-value pair holder */
|
||||
|
||||
// to follow std::variant requirements (not references, not array, not void)
|
||||
@ -521,7 +609,8 @@ public:
|
||||
template <std::ranges::contiguous_range R, std::ranges::input_range RecDelimT = std::string_view>
|
||||
std::error_code fromCharRange(const R& buffer, RecDelimT rec_delim = std::string_view("\n"))
|
||||
{
|
||||
return fromCharRange(buffer, KeyValueHolder::defaultDeserializeFunc, std::move(rec_delim));
|
||||
// return fromCharRange(buffer, KeyValueHolder::defaultDeserializeFunc, std::move(rec_delim));
|
||||
return fromCharRange(buffer, MccSimpleDeserializer{}.setRangeDelim(VALUE_ARRAY_DELIM), std::move(rec_delim));
|
||||
}
|
||||
|
||||
template <std::ranges::contiguous_range R,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user