parselink-old/include/parselink/proto/parser.h

96 lines
3.3 KiB
C++

//-----------------------------------------------------------------------------
// ___ __ _ _
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
// / ___/ (_| | | \__ \ __/ /__| | | | | <
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
//
//-----------------------------------------------------------------------------
// Author: Kurt Sassenrath
// Module: Proto
//
// Parser for extracting messages from msgpack.
//
// Note: Eventually, it would be nice to automatically generate the parser for
// message structures. Definitions below are templated to allow for this.
//
// Copyright (c) 2023 Kurt Sassenrath.
//
// License TBD.
//-----------------------------------------------------------------------------
#ifndef parselink_proto_parser_ad351d41fe4c72dd
#define parselink_proto_parser_ad351d41fe4c72dd
#include "parselink/logging.h"
#include "parselink/proto/error.h"
#include "parselink/proto/message.h"
#include "parselink/msgpack/core/unpacker.h"
#include <tl/expected.hpp>
#include <boost/pfr.hpp>
namespace parselink {
logging::logger& get_logger();
}
namespace msgpack {
template <parselink::proto::message_type M>
struct unpacker_adapter<M> {
static constexpr auto unpack(auto& unpacker) noexcept
-> tl::expected<M, error> {
auto verify_name = unpacker.template unpack<std::string_view>();
if (!verify_name || verify_name != M::message_name()) {
fmt::print("{} {}\n", verify_name, M::message_name());
return tl::make_unexpected(error::wrong_type);
}
auto mapsize = unpacker.template unpack<msgpack::map_desc>();
if (!mapsize) {
return tl::make_unexpected(error::wrong_type);
} else if (mapsize->count != boost::pfr::tuple_size_v<M>) {
return tl::make_unexpected(error::wrong_type);
}
return M{};
}
};
} // namespace msgpack
namespace parselink {
namespace proto {
////////////////////////////////////////////////////////////////////////////////
// Default parse template instantiation -- unsupported message.
////////////////////////////////////////////////////////////////////////////////
template <message_type M>
tl::expected<M, error> parse(std::span<std::byte const> data) noexcept {
return tl::make_unexpected(error::unsupported);
}
////////////////////////////////////////////////////////////////////////////////
// Currently-implemented message types.
////////////////////////////////////////////////////////////////////////////////
#define PARSELINK_PROTO_SUPPORTED_MESSAGE(msgtype) \
tl::expected<msgtype, error> parse_##msgtype( \
std::span<std::byte const> data) noexcept; \
template <> \
constexpr tl::expected<msgtype, error> parse( \
std::span<std::byte const> data) noexcept { \
return parse_##msgtype(data); \
}
PARSELINK_PROTO_SUPPORTED_MESSAGE(connect_message);
#undef PARSELINK_PROTO_SUPPORTED_MESSAGE
} // namespace proto
} // namespace parselink
#endif // parselink_proto_parser_ad351d41fe4c72dd