From 6874da27a3d0ad4d27a1bbb2ead1026eceeefb48 Mon Sep 17 00:00:00 2001 From: Kurt Sassenrath Date: Fri, 20 Oct 2023 00:34:44 -0700 Subject: [PATCH] Apply clang-format --- beastref.cpp | 290 ++--- include/parselink/logging.h | 50 +- include/parselink/logging/formatters.h | 43 +- include/parselink/logging/level.h | 22 +- include/parselink/logging/theme.h | 81 +- include/parselink/logging/traits.h | 14 +- include/parselink/msgpack/core/error.h | 6 +- include/parselink/msgpack/core/format.h | 573 +++++---- include/parselink/msgpack/core/reader.h | 453 ++++--- include/parselink/msgpack/core/writer.h | 224 ++-- include/parselink/msgpack/token.h | 2 +- include/parselink/msgpack/token/reader.h | 99 +- include/parselink/msgpack/token/type.h | 118 +- include/parselink/msgpack/token/views.h | 195 ++- include/parselink/msgpack/util/endianness.h | 26 +- include/parselink/proto/message.h | 16 +- include/parselink/proto/session.h | 14 +- include/parselink/server.h | 8 +- include/parselink/utility/argparse.h | 397 +++--- source/logging/logging.cpp | 20 +- source/main.cpp | 17 +- source/proto/session.cpp | 40 +- source/server.cpp | 124 +- tests/logging/logging.cpp | 80 +- tests/msgpack/rng.h | 17 +- tests/msgpack/test_reader_relaxed.cpp | 173 ++- tests/msgpack/test_reader_strict.cpp | 1240 ++++++++++--------- tests/msgpack/test_speed.cpp | 87 +- tests/msgpack/test_token.cpp | 60 +- tests/msgpack/test_token_reader.cpp | 180 ++- tests/msgpack/test_token_views.cpp | 69 +- tests/msgpack/test_utils.h | 16 +- tests/msgpack/test_writer.cpp | 417 ++++--- 33 files changed, 2546 insertions(+), 2625 deletions(-) diff --git a/beastref.cpp b/beastref.cpp index 9811ece..1c6e134 100644 --- a/beastref.cpp +++ b/beastref.cpp @@ -1,11 +1,11 @@ +#include +#include +#include #include #include #include -#include -#include #include -#include #include #include #include @@ -14,69 +14,57 @@ #include #include -namespace beast = boost::beast; // from -namespace http = beast::http; // from -namespace net = boost::asio; // from -using tcp = boost::asio::ip::tcp; // from +namespace beast = boost::beast; // from +namespace http = beast::http; // from +namespace net = boost::asio; // from +using tcp = boost::asio::ip::tcp; // from // Return a reasonable mime type based on the extension of a file. -beast::string_view -mime_type(beast::string_view path) -{ +beast::string_view mime_type(beast::string_view path) { using beast::iequals; - auto const ext = [&path] - { + auto const ext = [&path] { auto const pos = path.rfind("."); - if(pos == beast::string_view::npos) - return beast::string_view{}; + if (pos == beast::string_view::npos) return beast::string_view{}; return path.substr(pos); }(); - if(iequals(ext, ".htm")) return "text/html"; - if(iequals(ext, ".html")) return "text/html"; - if(iequals(ext, ".php")) return "text/html"; - if(iequals(ext, ".css")) return "text/css"; - if(iequals(ext, ".txt")) return "text/plain"; - if(iequals(ext, ".js")) return "application/javascript"; - if(iequals(ext, ".json")) return "application/json"; - if(iequals(ext, ".xml")) return "application/xml"; - if(iequals(ext, ".swf")) return "application/x-shockwave-flash"; - if(iequals(ext, ".flv")) return "video/x-flv"; - if(iequals(ext, ".png")) return "image/png"; - if(iequals(ext, ".jpe")) return "image/jpeg"; - if(iequals(ext, ".jpeg")) return "image/jpeg"; - if(iequals(ext, ".jpg")) return "image/jpeg"; - if(iequals(ext, ".gif")) return "image/gif"; - if(iequals(ext, ".bmp")) return "image/bmp"; - if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon"; - if(iequals(ext, ".tiff")) return "image/tiff"; - if(iequals(ext, ".tif")) return "image/tiff"; - if(iequals(ext, ".svg")) return "image/svg+xml"; - if(iequals(ext, ".svgz")) return "image/svg+xml"; + if (iequals(ext, ".htm")) return "text/html"; + if (iequals(ext, ".html")) return "text/html"; + if (iequals(ext, ".php")) return "text/html"; + if (iequals(ext, ".css")) return "text/css"; + if (iequals(ext, ".txt")) return "text/plain"; + if (iequals(ext, ".js")) return "application/javascript"; + if (iequals(ext, ".json")) return "application/json"; + if (iequals(ext, ".xml")) return "application/xml"; + if (iequals(ext, ".swf")) return "application/x-shockwave-flash"; + if (iequals(ext, ".flv")) return "video/x-flv"; + if (iequals(ext, ".png")) return "image/png"; + if (iequals(ext, ".jpe")) return "image/jpeg"; + if (iequals(ext, ".jpeg")) return "image/jpeg"; + if (iequals(ext, ".jpg")) return "image/jpeg"; + if (iequals(ext, ".gif")) return "image/gif"; + if (iequals(ext, ".bmp")) return "image/bmp"; + if (iequals(ext, ".ico")) return "image/vnd.microsoft.icon"; + if (iequals(ext, ".tiff")) return "image/tiff"; + if (iequals(ext, ".tif")) return "image/tiff"; + if (iequals(ext, ".svg")) return "image/svg+xml"; + if (iequals(ext, ".svgz")) return "image/svg+xml"; return "application/text"; } // Append an HTTP rel-path to a local filesystem path. // The returned path is normalized for the platform. -std::string -path_cat( - beast::string_view base, - beast::string_view path) -{ - if(base.empty()) - return std::string(path); +std::string path_cat(beast::string_view base, beast::string_view path) { + if (base.empty()) return std::string(path); std::string result(base); #ifdef BOOST_MSVC char constexpr path_separator = '\\'; - if(result.back() == path_separator) - result.resize(result.size() - 1); + if (result.back() == path_separator) result.resize(result.size() - 1); result.append(path.data(), path.size()); - for(auto& c : result) - if(c == '/') - c = path_separator; + for (auto& c : result) + if (c == '/') c = path_separator; #else char constexpr path_separator = '/'; - if(result.back() == path_separator) - result.resize(result.size() - 1); + if (result.back() == path_separator) result.resize(result.size() - 1); result.append(path.data(), path.size()); #endif return result; @@ -87,16 +75,12 @@ path_cat( // The concrete type of the response message (which depends on the // request), is type-erased in message_generator. template -http::message_generator -handle_request( - beast::string_view doc_root, - http::request>&& req) -{ +http::message_generator handle_request(beast::string_view doc_root, + http::request>&& req) { // Returns a bad request response - auto const bad_request = - [&req](beast::string_view why) - { - http::response res{http::status::bad_request, req.version()}; + auto const bad_request = [&req](beast::string_view why) { + http::response res{ + http::status::bad_request, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, "text/html"); res.keep_alive(req.keep_alive()); @@ -106,23 +90,22 @@ handle_request( }; // Returns a not found response - auto const not_found = - [&req](beast::string_view target) - { - http::response res{http::status::not_found, req.version()}; + auto const not_found = [&req](beast::string_view target) { + http::response res{ + http::status::not_found, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, "text/html"); res.keep_alive(req.keep_alive()); - res.body() = "The resource '" + std::string(target) + "' was not found."; + res.body() = + "The resource '" + std::string(target) + "' was not found."; res.prepare_payload(); return res; }; // Returns a server error response - auto const server_error = - [&req](beast::string_view what) - { - http::response res{http::status::internal_server_error, req.version()}; + auto const server_error = [&req](beast::string_view what) { + http::response res{ + http::status::internal_server_error, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, "text/html"); res.keep_alive(req.keep_alive()); @@ -132,20 +115,17 @@ handle_request( }; // Make sure we can handle the method - if( req.method() != http::verb::get && - req.method() != http::verb::head) + if (req.method() != http::verb::get && req.method() != http::verb::head) return bad_request("Unknown HTTP-method"); // Request path must be absolute and not contain "..". - if( req.target().empty() || - req.target()[0] != '/' || - req.target().find("..") != beast::string_view::npos) + if (req.target().empty() || req.target()[0] != '/' + || req.target().find("..") != beast::string_view::npos) return bad_request("Illegal request-target"); // Build the path to the requested file std::string path = path_cat(doc_root, req.target()); - if(req.target().back() == '/') - path.append("index.html"); + if (req.target().back() == '/') path.append("index.html"); // Attempt to open the file beast::error_code ec; @@ -153,19 +133,17 @@ handle_request( body.open(path.c_str(), beast::file_mode::scan, ec); // Handle the case where the file doesn't exist - if(ec == beast::errc::no_such_file_or_directory) + if (ec == beast::errc::no_such_file_or_directory) return not_found(req.target()); // Handle an unknown error - if(ec) - return server_error(ec.message()); + if (ec) return server_error(ec.message()); // Cache the size since we need it after the move auto const size = body.size(); // Respond to HEAD request - if(req.method() == http::verb::head) - { + if (req.method() == http::verb::head) { http::response res{http::status::ok, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, mime_type(path)); @@ -175,10 +153,9 @@ handle_request( } // Respond to GET request - http::response res{ - std::piecewise_construct, - std::make_tuple(std::move(body)), - std::make_tuple(http::status::ok, req.version())}; + http::response res{std::piecewise_construct, + std::make_tuple(std::move(body)), + std::make_tuple(http::status::ok, req.version())}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); res.set(http::field::content_type, mime_type(path)); res.content_length(size); @@ -189,15 +166,12 @@ handle_request( //------------------------------------------------------------------------------ // Report a failure -void -fail(beast::error_code ec, char const* what) -{ +void fail(beast::error_code ec, char const* what) { std::cerr << what << ": " << ec.message() << "\n"; } // Handles an HTTP server connection -class session : public std::enable_shared_from_this -{ +class session : public std::enable_shared_from_this { beast::tcp_stream stream_; beast::flat_buffer buffer_; std::shared_ptr doc_root_; @@ -205,31 +179,23 @@ class session : public std::enable_shared_from_this public: // Take ownership of the stream - session( - tcp::socket&& socket, - std::shared_ptr const& doc_root) - : stream_(std::move(socket)) - , doc_root_(doc_root) - { - } + session(tcp::socket&& socket, + std::shared_ptr const& doc_root) + : stream_(std::move(socket)) + , doc_root_(doc_root) {} // Start the asynchronous operation - void - run() - { + void run() { // We need to be executing within a strand to perform async operations // on the I/O objects in this session. Although not strictly necessary // for single-threaded contexts, this example code is written to be // thread-safe by default. net::dispatch(stream_.get_executor(), - beast::bind_front_handler( - &session::do_read, - shared_from_this())); + beast::bind_front_handler( + &session::do_read, shared_from_this())); } - void - do_read() - { + void do_read() { // Make the request empty before reading, // otherwise the operation behavior is undefined. req_ = {}; @@ -239,56 +205,38 @@ public: // Read a request http::async_read(stream_, buffer_, req_, - beast::bind_front_handler( - &session::on_read, - shared_from_this())); + beast::bind_front_handler( + &session::on_read, shared_from_this())); } - void - on_read( - beast::error_code ec, - std::size_t bytes_transferred) - { + void on_read(beast::error_code ec, std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); // This means they closed the connection - if(ec == http::error::end_of_stream) - return do_close(); + if (ec == http::error::end_of_stream) return do_close(); - if(ec) - return fail(ec, "read"); + if (ec) return fail(ec, "read"); // Send the response - send_response( - handle_request(*doc_root_, std::move(req_))); + send_response(handle_request(*doc_root_, std::move(req_))); } - void - send_response(http::message_generator&& msg) - { + void send_response(http::message_generator&& msg) { bool keep_alive = msg.keep_alive(); // Write the response - beast::async_write( - stream_, - std::move(msg), - beast::bind_front_handler( - &session::on_write, shared_from_this(), keep_alive)); + beast::async_write(stream_, std::move(msg), + beast::bind_front_handler( + &session::on_write, shared_from_this(), keep_alive)); } - void - on_write( - bool keep_alive, - beast::error_code ec, - std::size_t bytes_transferred) - { + void on_write(bool keep_alive, beast::error_code ec, + std::size_t bytes_transferred) { boost::ignore_unused(bytes_transferred); - if(ec) - return fail(ec, "write"); + if (ec) return fail(ec, "write"); - if(! keep_alive) - { + if (!keep_alive) { // This means we should close the connection, usually because // the response indicated the "Connection: close" semantic. return do_close(); @@ -298,9 +246,7 @@ public: do_read(); } - void - do_close() - { + void do_close() { // Send a TCP shutdown beast::error_code ec; stream_.socket().shutdown(tcp::socket::shutdown_send, ec); @@ -312,90 +258,66 @@ public: //------------------------------------------------------------------------------ // Accepts incoming connections and launches the sessions -class listener : public std::enable_shared_from_this -{ +class listener : public std::enable_shared_from_this { net::io_context& ioc_; tcp::acceptor acceptor_; std::shared_ptr doc_root_; public: - listener( - net::io_context& ioc, - tcp::endpoint endpoint, - std::shared_ptr const& doc_root) - : ioc_(ioc) - , acceptor_(net::make_strand(ioc)) - , doc_root_(doc_root) - { + listener(net::io_context& ioc, tcp::endpoint endpoint, + std::shared_ptr const& doc_root) + : ioc_(ioc) + , acceptor_(net::make_strand(ioc)) + , doc_root_(doc_root) { beast::error_code ec; // Open the acceptor acceptor_.open(endpoint.protocol(), ec); - if(ec) - { + if (ec) { fail(ec, "open"); return; } // Allow address reuse acceptor_.set_option(net::socket_base::reuse_address(true), ec); - if(ec) - { + if (ec) { fail(ec, "set_option"); return; } // Bind to the server address acceptor_.bind(endpoint, ec); - if(ec) - { + if (ec) { fail(ec, "bind"); return; } // Start listening for connections - acceptor_.listen( - net::socket_base::max_listen_connections, ec); - if(ec) - { + acceptor_.listen(net::socket_base::max_listen_connections, ec); + if (ec) { fail(ec, "listen"); return; } } // Start accepting incoming connections - void - run() - { - do_accept(); - } + void run() { do_accept(); } private: - void - do_accept() - { + void do_accept() { // The new connection gets its own strand - acceptor_.async_accept( - net::make_strand(ioc_), - beast::bind_front_handler( - &listener::on_accept, - shared_from_this())); + acceptor_.async_accept(net::make_strand(ioc_), + beast::bind_front_handler( + &listener::on_accept, shared_from_this())); } - void - on_accept(beast::error_code ec, tcp::socket socket) - { - if(ec) - { + void on_accept(beast::error_code ec, tcp::socket socket) { + if (ec) { fail(ec, "accept"); return; // To avoid infinite loop - } - else - { + } else { // Create the session and run it - std::make_shared( - std::move(socket), - doc_root_)->run(); + std::make_shared(std::move(socket), doc_root_)->run(); } // Accept another connection @@ -404,5 +326,3 @@ private: }; //------------------------------------------------------------------------------ - - diff --git a/include/parselink/logging.h b/include/parselink/logging.h index cb136cc..a8d1172 100644 --- a/include/parselink/logging.h +++ b/include/parselink/logging.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // @@ -14,21 +14,20 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef logging_982a89e400976f59 #define logging_982a89e400976f59 +#include "logging/formatters.h" +#include "logging/theme.h" +#include "logging/traits.h" #include #include #include #include #include -#include "logging/formatters.h" -#include "logging/theme.h" -#include "logging/traits.h" - namespace parselink { namespace logging { @@ -51,7 +50,9 @@ struct message { struct endpoint { virtual ~endpoint() = default; + virtual std::span buffer() { return {}; } + virtual void write(message const& msg) = 0; virtual bool colored() const noexcept = 0; level threshold{default_threshold}; @@ -64,27 +65,28 @@ public: // This constructor allows for an arbitrary number of logging endpoints // to be passed in. - logger(std::string_view name, - std::vector> eps); + logger(std::string_view name, std::vector> eps); template explicit logger(std::string_view name, Endpoints&&... eps) : logger(name, {std::forward(eps)...}) {} - template - requires (Level <= static_threshold) + template + requires(Level <= static_threshold) void log(fmt::format_string format, Args&&... args) const { - try_write(Level, format.get(), std::forward(args)...); + do_write(Level, format.get(), std::forward(args)...); } - template - requires (Level > static_threshold) + template + requires(Level > static_threshold) [[gnu::flatten]] void log(fmt::format_string, Args&&...) const {} -#define LOG_API(lvl) \ - template \ - [[gnu::always_inline]] void lvl(fmt::format_string&& format, Args&&... args) const { \ - log(std::forward(format), std::forward(args)...); \ +#define LOG_API(lvl) \ + template \ + [[gnu::always_inline]] void lvl( \ + fmt::format_string&& format, Args&&... args) const { \ + log(std::forward(format), \ + std::forward(args)...); \ } LOG_API(critical); @@ -100,8 +102,7 @@ public: void set_threshold(level new_threshold) noexcept; private: - - template + template void write_endpoint(std::shared_ptr const& endpoint, message msg, fmt::string_view format, Args&&... args) const { auto buff = endpoint->buffer(); @@ -114,16 +115,15 @@ private: endpoint->write(msg); } else { // Fill the static buffer. - fmt::vformat_to(buff.begin(), format, - fmt::make_format_args(args...)); + fmt::vformat_to( + buff.begin(), format, fmt::make_format_args(args...)); msg.message = std::string_view{buff.data(), buff.size()}; endpoint->write(msg); } } - template - void try_write(level level, fmt::string_view format, - Args&&... args) const { + template + void do_write(level level, fmt::string_view format, Args&&... args) const { message msg{level, std::chrono::system_clock::now(), name_}; for (auto const& ep : endpoints_) { if (level > ep->threshold) continue; diff --git a/include/parselink/logging/formatters.h b/include/parselink/logging/formatters.h index c747320..668bed4 100644 --- a/include/parselink/logging/formatters.h +++ b/include/parselink/logging/formatters.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // @@ -15,23 +15,22 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef logging_formatters_d22a64b1645a8134 #define logging_formatters_d22a64b1645a8134 -#include "traits.h" #include "theme.h" +#include "traits.h" +#include #include -#include - // Simple wrapper for error strings to be formatted like any other string_view. template <> struct fmt::formatter : fmt::formatter { - template + template constexpr auto format(auto const& v, FormatContext& ctx) const { return fmt::formatter::format(v.v, ctx); } @@ -45,14 +44,13 @@ struct fmt::formatter // // Logging `color` will yield "Color::Green" template -requires std::is_enum_v + requires std::is_enum_v struct fmt::formatter : fmt::formatter { - template + template auto format(E const v, FormatContext& ctx) const { - auto str = [v]{ - return fmt::format("{}::{}", - magic_enum::enum_type_name(), - magic_enum::enum_name(v)); + auto str = [v] { + return fmt::format("{}::{}", magic_enum::enum_type_name(), + magic_enum::enum_name(v)); }(); return fmt::formatter::format(str, ctx); } @@ -66,11 +64,12 @@ struct fmt::formatter : fmt::formatter { // // Logging `enum_name_only{color}` will yield "Green" template -requires std::is_enum_v + requires std::is_enum_v struct fmt::formatter> : fmt::formatter { using enum_name_only = parselink::logging::enum_name_only; - template + + template auto format(enum_name_only const v, FormatContext& ctx) const { return fmt::formatter::format( magic_enum::enum_name(v.v), ctx); @@ -79,7 +78,7 @@ struct fmt::formatter> template <> struct fmt::formatter : fmt::formatter { - template + template auto format(auto const& v, FormatContext& ctx) const { return fmt::formatter::format(v.message(), ctx); } @@ -89,7 +88,7 @@ struct fmt::formatter : fmt::formatter { // string. template <> struct fmt::formatter : fmt::formatter { - template + template auto format(std::errc const& v, FormatContext& ctx) const { return fmt::formatter::format( std::make_error_code(v), ctx); @@ -104,7 +103,7 @@ struct fmt::formatter { return ctx.begin(); } - template + template auto format(std::byte const v, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "0x{:0x}", std::uint8_t(v)); } @@ -113,7 +112,7 @@ struct fmt::formatter { // Support printing raw/smart pointers without needing to wrap them in fmt::ptr template struct fmt::formatter : fmt::formatter { - template + template auto format(T const& v, FormatContext& ctx) const { return fmt::formatter::format(fmt::ptr(v), ctx); } @@ -127,7 +126,7 @@ struct fmt::formatter> { return ctx.begin(); } - template + template auto format(tl::expected const& v, FormatContext& ctx) const { if (v) { return fmt::format_to(ctx.out(), "{}", @@ -141,8 +140,8 @@ struct fmt::formatter> { // Support format_arg wrappers, which will be used to colorize output. template -struct fmt::formatter> : - fmt::formatter::type> { +struct fmt::formatter> + : fmt::formatter::type> { using format_arg_type = parselink::logging::format_arg; using resolved_type = typename format_arg_type::type; diff --git a/include/parselink/logging/level.h b/include/parselink/logging/level.h index 8f023ac..6b78930 100644 --- a/include/parselink/logging/level.h +++ b/include/parselink/logging/level.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // @@ -16,7 +16,7 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef level_9f090ff308e53a57 #define level_9f090ff308e53a57 @@ -25,14 +25,14 @@ namespace parselink { namespace logging { enum class level { - silent, // "Virtual" level used to suppress all logging output. - critical, // Indicates a fatal error occurred. Crash likely. - error, // Indicates a non-fatal error occurred. - warning, // Indicates potentially incorrect/unintentional behavior. - info, // Indicates general information. - verbose, // Noisier/potentially unimportant information. - debug, // Information intended for debugging purposes only. - trace // Tracer-like levels of verbosity may impact performance. + silent, // "Virtual" level used to suppress all logging output. + critical, // Indicates a fatal error occurred. Crash likely. + error, // Indicates a non-fatal error occurred. + warning, // Indicates potentially incorrect/unintentional behavior. + info, // Indicates general information. + verbose, // Noisier/potentially unimportant information. + debug, // Information intended for debugging purposes only. + trace // Tracer-like levels of verbosity may impact performance. }; } // namespace logging diff --git a/include/parselink/logging/theme.h b/include/parselink/logging/theme.h index 247914e..f12bb8c 100644 --- a/include/parselink/logging/theme.h +++ b/include/parselink/logging/theme.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // @@ -24,42 +24,49 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef log_theme_8e9601cc066b20bf #define log_theme_8e9601cc066b20bf #include "level.h" #include "traits.h" - -#include - -#include - #include #include +#include +#include + namespace parselink { namespace logging { template -struct format_arg{ +struct format_arg { using type = std::decay_t; - constexpr format_arg(type const& t) : v(t) {} + + constexpr format_arg(type const& t) + : v(t) {} + type const& v; }; template T> struct format_arg { using type = std::string_view; - constexpr format_arg(T&& t) noexcept : v(t) {} + + constexpr format_arg(T&& t) noexcept + : v(t) {} + type v; }; template struct format_arg { using type = void const*; - constexpr format_arg(T const& t) noexcept : v(fmt::ptr(t)) {} + + constexpr format_arg(T const& t) noexcept + : v(fmt::ptr(t)) {} + void const* v; }; @@ -72,7 +79,7 @@ struct static_theme { }; template -requires (!std::same_as) + requires(!std::same_as) struct theme : static_theme {}; template <> @@ -85,7 +92,7 @@ template struct theme : static_theme {}; template -requires std::is_enum_v + requires std::is_enum_v struct theme : static_theme {}; // Errors @@ -98,7 +105,6 @@ struct theme : static_theme {}; template <> struct theme : static_theme {}; - template <> struct theme { static constexpr auto style(bool l) noexcept { @@ -108,37 +114,40 @@ struct theme { template <> struct theme> { + // clang-format off constexpr static fmt::color colors[] = { - fmt::color::black, - fmt::color::red, - fmt::color::fire_brick, - fmt::color::golden_rod, - fmt::color::light_sky_blue, - fmt::color::lime_green, - fmt::color::pink, - fmt::color::slate_gray - }; + fmt::color::black, + fmt::color::red, + fmt::color::fire_brick, + fmt::color::golden_rod, + fmt::color::light_sky_blue, + fmt::color::lime_green, + fmt::color::pink, + fmt::color::slate_gray }; + + // clang-format on + static constexpr auto style(auto l) noexcept { return fmt::fg(*std::next(std::begin(colors), size_t(l.v))); } }; template -concept has_static_theme = - std::convertible_to>::style)>; +concept has_static_theme = std::convertible_to>::style)>; template -concept has_dynamic_theme = requires (T const& t) { - { theme>::style(t) } - -> std::convertible_to; +concept has_dynamic_theme = requires(T const& t) { + { + theme>::style(t) + } -> std::convertible_to; }; template concept has_theme = has_static_theme || has_dynamic_theme; template -requires (has_theme) + requires(has_theme) struct theme> : theme {}; template @@ -156,12 +165,12 @@ constexpr auto get_theme(T const& value) { return theme::style(value); } -[[gnu::always_inline]] constexpr auto styled(fmt::text_style const& style, - auto out) { +[[gnu::always_inline]] constexpr auto styled( + fmt::text_style const& style, auto out) { if (style.has_foreground()) { - auto foreground = - fmt::detail::make_foreground_color(style.get_foreground()); - out = std::copy(foreground.begin(), foreground.end(), out); + auto foreground = fmt::detail::make_foreground_color( + style.get_foreground()); + out = std::copy(foreground.begin(), foreground.end(), out); } return out; } diff --git a/include/parselink/logging/traits.h b/include/parselink/logging/traits.h index b05df02..71c14b7 100644 --- a/include/parselink/logging/traits.h +++ b/include/parselink/logging/traits.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // @@ -14,13 +14,13 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef logging_traits_34e410874c0179c6 #define logging_traits_34e410874c0179c6 -#include #include +#include namespace parselink { namespace logging { @@ -33,7 +33,7 @@ namespace logging { // logger.log<...>("value: {}", v); // logs "value: Foo::Bar" // logger.log<...>("value: {}", enum_name_only{v}); // logs "value: Bar" template -requires std::is_enum_v + requires std::is_enum_v struct enum_name_only { E v; }; @@ -45,7 +45,9 @@ enum_name_only(E) -> enum_name_only; // a normal string. struct error_str { template T> - error_str(T&& t) : v(std::forward(t)) {} + error_str(T&& t) + : v(std::forward(t)) {} + std::string_view v; }; diff --git a/include/parselink/msgpack/core/error.h b/include/parselink/msgpack/core/error.h index fa5d840..07c8a88 100644 --- a/include/parselink/msgpack/core/error.h +++ b/include/parselink/msgpack/core/error.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -14,7 +14,7 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_error_3fae420b0427164e #define msgpack_error_3fae420b0427164e diff --git a/include/parselink/msgpack/core/format.h b/include/parselink/msgpack/core/format.h index 5dd9e34..845b1f8 100644 --- a/include/parselink/msgpack/core/format.h +++ b/include/parselink/msgpack/core/format.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -14,7 +14,7 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_format_849b5c5238d8212 #define msgpack_format_849b5c5238d8212 @@ -27,327 +27,366 @@ namespace msgpack { -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Supporting types/tags for formats -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- struct nil { nil() = default; // This constructor is used by the reader implementation. - nil(auto) {}; + nil(auto){}; }; + struct invalid {}; + using boolean = bool; struct array_desc { constexpr array_desc() noexcept = default; - constexpr array_desc(auto sz) noexcept : count(std::size_t(sz)) {}; + constexpr array_desc(auto sz) noexcept + : count(std::size_t(sz)){}; // This constructor is implemented for use by reader - constexpr array_desc(auto, auto sz) noexcept : count(std::size_t(sz)) {}; + constexpr array_desc(auto, auto sz) noexcept + : count(std::size_t(sz)){}; + constexpr bool operator==(array_desc const& other) const noexcept { return count == other.count; } + std::size_t count = 0; }; struct map_desc { constexpr map_desc() noexcept = default; - constexpr map_desc(auto sz) noexcept : count(std::size_t(sz)) {}; + constexpr map_desc(auto sz) noexcept + : count(std::size_t(sz)){}; // This constructor is implemented for use by reader - constexpr map_desc(auto, auto sz) noexcept : count(std::size_t(sz)) {}; + constexpr map_desc(auto, auto sz) noexcept + : count(std::size_t(sz)){}; std::size_t count = 0; }; namespace format { - // Classification of the format type. Used by the token API to distinguish - // different formats. - enum class type : std::uint8_t { - invalid, - unsigned_int, - signed_int, - string, - binary, - nil, - boolean, - array, - map, - array_view, - map_view, - }; +// Classification of the format type. Used by the token API to distinguish +// different formats. +enum class type : std::uint8_t { + invalid, + unsigned_int, + signed_int, + string, + binary, + nil, + boolean, + array, + map, + array_view, + map_view, +}; - // Flags that may control the behavior of readers/writers. - enum flag : std::uint8_t { - apply_mask = 1, - fixed_size = 2, - }; +// Flags that may control the behavior of readers/writers. +enum flag : std::uint8_t { + apply_mask = 1, + fixed_size = 2, +}; - // MessagePack formats break down into one of the following schemes: - // Marker byte + Fixed-length value - // Marker byte + Fixed-length payload length + payload - // - // In addition, there are "fix" types that embed the literal value or the - // payload length within the marker byte. - enum payload : std::uint8_t { - fixed, - variable - }; +// MessagePack formats break down into one of the following schemes: +// Marker byte + Fixed-length value +// Marker byte + Fixed-length payload length + payload +// +// In addition, there are "fix" types that embed the literal value or the +// payload length within the marker byte. +enum payload : std::uint8_t { fixed, variable }; - // Base structure for all MessagePack formats to inherit from. - struct base_format { - constexpr static flag flags = {}; - }; +// Base structure for all MessagePack formats to inherit from. +struct base_format { + constexpr static flag flags = {}; +}; - // Traits describing a particular format. - struct traits { - std::uint8_t flags{}; - std::uint8_t size{}; - std::byte mask{}; - type token_type{}; - constexpr auto operator<=>(traits const&) const noexcept = default; - }; +// Traits describing a particular format. +struct traits { + std::uint8_t flags{}; + std::uint8_t size{}; + std::byte mask{}; + type token_type{}; + constexpr auto operator<=>(traits const&) const noexcept = default; +}; - // "Sentinel" traits instance indicating no trait found - constexpr static traits no_traits {}; +// "Sentinel" traits instance indicating no trait found +constexpr static traits no_traits{}; - struct fixtype_format : base_format {}; +struct fixtype_format : base_format {}; - template - struct resolve_token_type { - constexpr static type value = type::invalid; - }; +template +struct resolve_token_type { + constexpr static type value = type::invalid; +}; - template - struct resolve_token_type { - constexpr static type value = std::is_signed_v ? - type::signed_int : type::unsigned_int; - }; +template +struct resolve_token_type { + constexpr static type value = + std::is_signed_v ? type::signed_int : type::unsigned_int; +}; - template <> - struct resolve_token_type { - constexpr static type value = type::string; - }; +template <> +struct resolve_token_type { + constexpr static type value = type::string; +}; - template <> - struct resolve_token_type> { - constexpr static type value = type::binary; - }; +template <> +struct resolve_token_type> { + constexpr static type value = type::binary; +}; - template <> - struct resolve_token_type { - constexpr static type value = type::boolean; - }; +template <> +struct resolve_token_type { + constexpr static type value = type::boolean; +}; - template <> - struct resolve_token_type { - constexpr static type value = type::nil; - }; +template <> +struct resolve_token_type { + constexpr static type value = type::nil; +}; - template <> - struct resolve_token_type { - constexpr static type value = type::invalid; - }; +template <> +struct resolve_token_type { + constexpr static type value = type::invalid; +}; - template <> - struct resolve_token_type { - constexpr static type value = type::array; - }; +template <> +struct resolve_token_type { + constexpr static type value = type::array; +}; - template <> - struct resolve_token_type { - constexpr static type value = type::map; - }; +template <> +struct resolve_token_type { + constexpr static type value = type::map; +}; - template - constexpr static auto resolve_type_v = resolve_token_type::value; +template +constexpr static auto resolve_type_v = resolve_token_type::value; - // The library's representation of certain data types does not always - // match the underlying data serialized in the message. For example, - // arrays and maps are encoded as a marker byte + fixed length value, but - // msgpack will present them wrapped in a structure for stronger type - // semantics. +// The library's representation of certain data types does not always +// match the underlying data serialized in the message. For example, +// arrays and maps are encoded as a marker byte + fixed length value, but +// msgpack will present them wrapped in a structure for stronger type +// semantics. - template - struct format : base_format { - using first_type = First; - using value_type = Value; // Can be overridden - constexpr static std::byte marker{Marker}; - constexpr static payload payload_type{payload::fixed}; - constexpr static std::uint8_t flags{}; - }; +template +struct format : base_format { + using first_type = First; + using value_type = Value; // Can be overridden + constexpr static std::byte marker{Marker}; + constexpr static payload payload_type{payload::fixed}; + constexpr static std::uint8_t flags{}; +}; - template - struct fixtype : fixtype_format { - using first_type = First; - using value_type = first_type; // Can be overridden - constexpr static std::byte marker{Marker}; - constexpr static std::byte mask{Mask}; - constexpr static payload payload_type{payload::fixed}; - constexpr static auto flags{flag::apply_mask}; - }; +template +struct fixtype : fixtype_format { + using first_type = First; + using value_type = first_type; // Can be overridden + constexpr static std::byte marker{Marker}; + constexpr static std::byte mask{Mask}; + constexpr static payload payload_type{payload::fixed}; + constexpr static auto flags{flag::apply_mask}; +}; - /* - * Integral types - */ +/* + * Integral types + */ - // Positive/negative fixint represent the literal value specified, do not - // need to mask it off. - struct positive_fixint : fixtype<0x00, 0x7f> { - constexpr static flag flags{}; - }; - struct negative_fixint : fixtype<0xe0, 0x1f, std::int8_t> { - constexpr static flag flags{}; - }; +// Positive/negative fixint represent the literal value specified, do not +// need to mask it off. +struct positive_fixint : fixtype<0x00, 0x7f> { + constexpr static flag flags{}; +}; - struct uint8 : format<0xcc, std::uint8_t> {}; - struct uint16 : format<0xcd, std::uint16_t> {}; - struct uint32 : format<0xce, std::uint32_t> {}; - struct uint64 : format<0xcf, std::uint64_t> {}; +struct negative_fixint : fixtype<0xe0, 0x1f, std::int8_t> { + constexpr static flag flags{}; +}; - struct int8 : format<0xd0, std::int8_t> {}; - struct int16 : format<0xd1, std::int16_t> {}; - struct int32 : format<0xd2, std::int32_t> {}; - struct int64 : format<0xd3, std::int64_t> {}; +struct uint8 : format<0xcc, std::uint8_t> {}; - /* - * Other primitive types - */ - struct nil : fixtype<0xc0, 0x00> { - using value_type = msgpack::nil; - constexpr static flag flags{flag::fixed_size | flag::apply_mask}; - }; +struct uint16 : format<0xcd, std::uint16_t> {}; - struct invalid : fixtype<0xc1, 0x00> { - using value_type = msgpack::invalid; - constexpr static flag flags{flag::fixed_size | flag::apply_mask}; - }; +struct uint32 : format<0xce, std::uint32_t> {}; - struct boolean : fixtype<0xc2, 0x01> { - using value_type = bool; - constexpr static flag flags{flag::fixed_size | flag::apply_mask}; - }; +struct uint64 : format<0xcf, std::uint64_t> {}; - /* - * Maps - */ +struct int8 : format<0xd0, std::int8_t> {}; - template struct map_format : Fmt { - using value_type = map_desc; - }; +struct int16 : format<0xd1, std::int16_t> {}; - struct fixmap : map_format> {}; - struct map16 : map_format> {}; - struct map32 : map_format> {}; +struct int32 : format<0xd2, std::int32_t> {}; - /* - * Arrays - */ +struct int64 : format<0xd3, std::int64_t> {}; - template struct array_format : Fmt { - using value_type = array_desc; - }; +/* + * Other primitive types + */ +struct nil : fixtype<0xc0, 0x00> { + using value_type = msgpack::nil; + constexpr static flag flags{flag::fixed_size | flag::apply_mask}; +}; - struct fixarray : array_format> {}; - struct array16 : array_format> {}; - struct array32 : array_format> {}; +struct invalid : fixtype<0xc1, 0x00> { + using value_type = msgpack::invalid; + constexpr static flag flags{flag::fixed_size | flag::apply_mask}; +}; - /* - * Strings - */ +struct boolean : fixtype<0xc2, 0x01> { + using value_type = bool; + constexpr static flag flags{flag::fixed_size | flag::apply_mask}; +}; - template struct string_format : Fmt { - using value_type = std::string_view; - constexpr static auto payload_type = payload::variable; - }; +/* + * Maps + */ +template +struct map_format : Fmt { + using value_type = map_desc; +}; - struct fixstr : string_format> {}; - struct str8 : string_format> {}; - struct str16 : string_format> {}; - struct str32 : string_format> {}; +struct fixmap : map_format> {}; - /* - * Binary arrays - */ +struct map16 : map_format> {}; - template struct bin_format : Fmt { - using value_type = std::span; - constexpr static auto payload_type = payload::variable; - }; +struct map32 : map_format> {}; - struct bin8 : bin_format> {}; - struct bin16 : bin_format> {}; - struct bin32 : bin_format> {}; +/* + * Arrays + */ - /* - * Extension types, not yet supported. - */ +template +struct array_format : Fmt { + using value_type = array_desc; +}; - template struct unimplemented_format : Fmt {}; +struct fixarray : array_format> {}; - struct fixext1 : unimplemented_format> {}; - struct fixext2 : unimplemented_format> {}; - struct fixext4 : unimplemented_format> {}; - struct fixext8 : unimplemented_format> {}; - struct fixext16 : unimplemented_format> {}; - struct ext8 : unimplemented_format> {}; - struct ext16 : unimplemented_format> {}; - struct ext32 : unimplemented_format> {}; +struct array16 : array_format> {}; - template - struct unimplemented : std::false_type {}; +struct array32 : array_format> {}; - template - struct unimplemented> : std::true_type {}; +/* + * Strings + */ + +template +struct string_format : Fmt { + using value_type = std::string_view; + constexpr static auto payload_type = payload::variable; +}; + +struct fixstr : string_format> {}; + +struct str8 : string_format> {}; + +struct str16 : string_format> {}; + +struct str32 : string_format> {}; + +/* + * Binary arrays + */ + +template +struct bin_format : Fmt { + using value_type = std::span; + constexpr static auto payload_type = payload::variable; +}; + +struct bin8 : bin_format> {}; + +struct bin16 : bin_format> {}; + +struct bin32 : bin_format> {}; + +/* + * Extension types, not yet supported. + */ + +template +struct unimplemented_format : Fmt {}; + +struct fixext1 : unimplemented_format> {}; + +struct fixext2 : unimplemented_format> {}; + +struct fixext4 : unimplemented_format> {}; + +struct fixext8 : unimplemented_format> {}; + +struct fixext16 : unimplemented_format> {}; + +struct ext8 : unimplemented_format> {}; + +struct ext16 : unimplemented_format> {}; + +struct ext32 : unimplemented_format> {}; + +template +struct unimplemented : std::false_type {}; + +template +struct unimplemented> : std::true_type {}; namespace detail { - // Simple typelist for looking up compatible types. - // TODO: Use traits to generate the compatibility list automatically? - template - struct type_list_entry { using type = T; }; +// Simple typelist for looking up compatible types. +// TODO: Use traits to generate the compatibility list automatically? +template +struct type_list_entry { + using type = T; +}; - template - struct type_list_impl; +template +struct type_list_impl; - template - struct type_list_impl, Ts...> : - type_list_entry... { - static constexpr auto size = sizeof...(Ts); - }; +template +struct type_list_impl, Ts...> + : type_list_entry... { + static constexpr auto size = sizeof...(Ts); +}; - template struct typelist_lookup_tag { using type = T; }; +template +struct typelist_lookup_tag { + using type = T; +}; - template - typelist_lookup_tag typelist_lookup(type_list_entry const&); +template +typelist_lookup_tag typelist_lookup(type_list_entry const&); - template - using type_list_at = typename decltype( - typelist_lookup(std::declval()))::type; +template +using type_list_at = + typename decltype(typelist_lookup(std::declval()))::type; - template - using type_list = detail::type_list_impl< - std::make_index_sequence, Ts...>; +template +using type_list = + detail::type_list_impl, Ts...>; - template typename> - struct filter_type_list; +template typename> +struct filter_type_list; - template typename Predicate> - struct filter_type_list, type_list, Predicate> { - using type = type_list; - }; +template typename Predicate> +struct filter_type_list, type_list, Predicate> { + using type = type_list; +}; - template typename Predicate> - struct filter_type_list, type_list, Predicate> { - using type = typename std::conditional_t< - Predicate::value, - filter_type_list, type_list, Predicate>, - filter_type_list, type_list, Predicate>>::type; - }; +template typename Predicate> +struct filter_type_list, type_list, Predicate> { + using type = typename std::conditional_t::value, + filter_type_list, type_list, + Predicate>, + filter_type_list, type_list, + Predicate>>::type; +}; - template typename Predicate> - using filter = filter_type_list, Predicate>; +template typename Predicate> +using filter = filter_type_list, Predicate>; - template typename Predicate> - using filter_t = typename filter::type; +template typename Predicate> +using filter_t = typename filter::type; } // namespace detail } // namespace format @@ -358,35 +397,33 @@ template concept is_fixtype = std::is_base_of_v; namespace format { - // This template instantiates a format::traits object for a given format. - // This should only occur once per format type, and should happen at - // compile time. - // - // This isn't the prettiest way to go about it. - template - inline traits const& get_traits() noexcept { - constexpr static auto inst = []{ - // Fixtypes define the size within the identifier byte, so the - // trait size must be zero. - auto size = is_fixtype ? - 0 : sizeof(typename Format::first_type); +// This template instantiates a format::traits object for a given format. +// This should only occur once per format type, and should happen at +// compile time. +// +// This isn't the prettiest way to go about it. +template +inline traits const& get_traits() noexcept { + constexpr static auto inst = [] { + // Fixtypes define the size within the identifier byte, so the + // trait size must be zero. + auto size = + is_fixtype ? 0 : sizeof(typename Format::first_type); - traits inst{ - .flags = Format::flags, + traits inst{.flags = Format::flags, .size = std::uint8_t(size), - .token_type = resolve_type_v - }; - // Add in the fixed_size flag for integral types. - if constexpr (std::is_integral_v) { - inst.flags |= flag::fixed_size; - } - if constexpr (is_fixtype) { - inst.mask = Format::mask; - } - return inst; - }(); + .token_type = resolve_type_v}; + // Add in the fixed_size flag for integral types. + if constexpr (std::is_integral_v) { + inst.flags |= flag::fixed_size; + } + if constexpr (is_fixtype) { + inst.mask = Format::mask; + } return inst; - }; + }(); + return inst; +}; } // namespace format template diff --git a/include/parselink/msgpack/core/reader.h b/include/parselink/msgpack/core/reader.h index d97db87..1f97047 100644 --- a/include/parselink/msgpack/core/reader.h +++ b/include/parselink/msgpack/core/reader.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -14,13 +14,13 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_core_reader_6c2f66f02585565 #define msgpack_core_reader_6c2f66f02585565 +#include "../util/endianness.h" #include "error.h" #include "format.h" -#include "../util/endianness.h" #include @@ -35,268 +35,265 @@ namespace msgpack { */ namespace reader_policy { struct relaxed {}; // Similar formats are acceptable. + struct strict {}; // Formats must exactly match the caller's request. } // namespace reader_policy namespace detail { - // Generic mechanism for reading a number of bytes out of an interator. - template - constexpr inline decltype(auto) read_bytes(Itr& inp) noexcept { - std::array out; - auto const end = inp + N; - auto dst = out.begin(); - while (inp != end) { - *dst = std::byte{*inp}; - ++dst; ++inp; - } - return out; +// Generic mechanism for reading a number of bytes out of an interator. +template +constexpr inline decltype(auto) read_bytes(Itr& inp) noexcept { + std::array out; + auto const end = inp + N; + auto dst = out.begin(); + while (inp != end) { + *dst = std::byte{*inp}; + ++dst; + ++inp; + } + return out; +} + +// Read an integral type out of the iterator. +template +constexpr inline decltype(auto) read_integral(Itr& inp) noexcept { + constexpr auto N = sizeof(T); + if constexpr (sizeof(T) == 1) { + return T(*inp++); + } else { + return be_to_host(::detail::value_cast(read_bytes(inp))); + } +} + +// This helper structure provides a customization point for converting an +// iterator to some other type (e.g. a pointer) in the event that the +// final format does not have a suitable constructor. It's only currently +// used for string_view, but may be overridden on platforms that provide +// their own types. +template +struct iterator_adapter { + static constexpr auto convert(Iter itr) { return itr; } +}; + +template +struct iterator_adapter { + static constexpr auto convert(Iter itr) { + return ::detail::value_cast(&*itr); + } +}; + +template +using expected = tl::expected; + +template +constexpr inline bool accept(Iter& itr) noexcept { + if constexpr (is_fixtype) { + // Don't advance the iterator -- part of the format is locked away + // within the format byte. + return (std::byte{*itr} & ~F::mask) == F::marker; + } else { + // Advance the iterator past the format byte. + return std::byte{*itr++} == F::marker; + } +} + +// Read a value from a MessagePack message. Assumes that itr != end to +// start with. +template + requires(!format::unimplemented::value) +constexpr inline auto read(Iter& itr, Iter const end) noexcept + -> expected { + // Copy off the iterator. Update it at the end _if_ everything goes + // smoothly. + auto cur = itr; + if (!accept(cur)) return tl::make_unexpected(error::wrong_type); + + // First thing's first. Read the format's "first_type", which is either + // the payload or the length of the payload. Ensure we have enough data + // from the span before we do so, though. + using first_type = typename F::first_type; + using value_type = typename F::value_type; + using diff_type = typename std::iterator_traits::difference_type; + if (std::distance(cur, end) < diff_type{sizeof(first_type)}) { + return tl::make_unexpected(error::incomplete_message); } - // Read an integral type out of the iterator. - template - constexpr inline decltype(auto) read_integral(Itr& inp) noexcept { - constexpr auto N = sizeof(T); - if constexpr (sizeof(T) == 1) { - return T(*inp++); - } else { - return be_to_host(::detail::value_cast(read_bytes(inp))); - } + auto f = read_integral(cur); + if constexpr (is_fixtype && (F::flags & format::flag::apply_mask)) { + f &= decltype(f)(F::mask); } - - // This helper structure provides a customization point for converting an - // iterator to some other type (e.g. a pointer) in the event that the - // final format does not have a suitable constructor. It's only currently - // used for string_view, but may be overridden on platforms that provide - // their own types. - template - struct iterator_adapter { - static constexpr auto convert(Iter itr) { return itr; } - }; - - template - struct iterator_adapter { - static constexpr auto convert(Iter itr) { - return ::detail::value_cast(&*itr); } - }; - - template - using expected = tl::expected; - - template - constexpr inline bool accept(Iter& itr) noexcept { - if constexpr (is_fixtype) { - // Don't advance the iterator -- part of the format is locked away - // within the format byte. - return (std::byte{*itr} & ~F::mask) == F::marker; - } else { - // Advance the iterator past the format byte. - return std::byte{*itr++} == F::marker; - } - } - - // Read a value from a MessagePack message. Assumes that itr != end to - // start with. - template - requires (!format::unimplemented::value) - constexpr inline auto read(Iter& itr, Iter const end) noexcept -> - expected { - // Copy off the iterator. Update it at the end _if_ everything goes - // smoothly. - auto cur = itr; - if (!accept(cur)) return tl::make_unexpected(error::wrong_type); - - // First thing's first. Read the format's "first_type", which is either - // the payload or the length of the payload. Ensure we have enough data - // from the span before we do so, though. - using first_type = typename F::first_type; - using value_type = typename F::value_type; - using diff_type = typename std::iterator_traits::difference_type; - if (std::distance(cur, end) < diff_type{sizeof(first_type)}) { + if constexpr (F::payload_type == format::payload::fixed) { + // We've read all we need to read. Update itr and return the value. + itr = cur; + return value_type(f); + } else { + // We're reading a variable length payload. `f` is the length of the + // payload. Ensure that the span has enough data and construct the + // value_type accordingly. + if (std::distance(cur, end) < diff_type{f}) { return tl::make_unexpected(error::incomplete_message); } - auto f = read_integral(cur); - if constexpr (is_fixtype && (F::flags & format::flag::apply_mask)) { - f &= decltype(f)(F::mask); - } + itr = cur + f; + using adapt = iterator_adapter; + return value_type(adapt::convert(cur), f); + } +} - if constexpr (F::payload_type == format::payload::fixed) { - // We've read all we need to read. Update itr and return the value. - itr = cur; - return value_type(f); - } else { - // We're reading a variable length payload. `f` is the length of the - // payload. Ensure that the span has enough data and construct the - // value_type accordingly. - if (std::distance(cur, end) < diff_type{f}) { - return tl::make_unexpected(error::incomplete_message); - } +// "Relaxed" reader policies allow for certain conversions to take place +// at runtime. For instance, any smaller type of the same category is +// allowed. +// +// TODO: Possible improvement to readability; specify a single format list +// containing all formats, and filter them down for each instantiated +// format. Note that this would probably have compile-time performance +// implications. - itr = cur + f; - using adapt = iterator_adapter; - return value_type(adapt::convert(cur), f); - } +template +struct relaxed_conversions {}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = + format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = + format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template <> +struct relaxed_conversions { + using type_list = format_list; +}; + +template +concept has_conversions = format_type && requires { + typename relaxed_conversions::type_list; +}; + +template +struct reader_policy_traits {}; + +template <> +struct reader_policy_traits { + template + constexpr static bool accept(Iter itr) noexcept { + return detail::accept(itr); } - // "Relaxed" reader policies allow for certain conversions to take place - // at runtime. For instance, any smaller type of the same category is - // allowed. - // - // TODO: Possible improvement to readability; specify a single format list - // containing all formats, and filter them down for each instantiated - // format. Note that this would probably have compile-time performance - // implications. - - template - struct relaxed_conversions {}; - - template <> - struct relaxed_conversions { - using type_list = format_list; + template + constexpr static decltype(auto) read(Iter& itr, Iter const end) noexcept { + return detail::read(itr, end); }; +}; - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template <> - struct relaxed_conversions { - using type_list = format_list; - }; - - template - concept has_conversions = format_type && requires { - typename relaxed_conversions::type_list; - }; - - template - struct reader_policy_traits {}; - - template <> - struct reader_policy_traits { - template - constexpr static bool accept(Iter itr) noexcept { - return detail::accept(itr); +template +constexpr static auto relaxed_read_impl(Iter& itr, Iter const end) noexcept + -> expected { + if constexpr (I < fmtlist::size) { + using this_format = format_list_at; + auto v = detail::read(itr, end); + if (v.has_value()) { + return v.value(); + } else if (v.error() == error::wrong_type) { + return relaxed_read_impl(itr, end); + } else { + return v; } + } else { + return tl::make_unexpected(error::wrong_type); + } +} - template - constexpr static decltype(auto) read(Iter& itr, Iter const end) - noexcept { +template <> +struct reader_policy_traits { + template + constexpr static decltype(auto) read(Iter& itr, Iter const& end) noexcept { + if constexpr (has_conversions) { + using format_list = typename relaxed_conversions::type_list; + return relaxed_read_impl(itr, end); + } else { + // Fall back on strict policy return detail::read(itr, end); - }; - }; - - template - constexpr static auto relaxed_read_impl(Iter& itr, Iter const end) - noexcept -> expected { - if constexpr (I < fmtlist::size) { - using this_format = format_list_at; - auto v = detail::read(itr, end); - if (v.has_value()) { - return v.value(); - } else if (v.error() == error::wrong_type) { - return relaxed_read_impl(itr, end); - } else { - return v; - } - } else { - return tl::make_unexpected(error::wrong_type); } } - - template <> - struct reader_policy_traits { - template - constexpr static decltype(auto) read(Iter& itr, Iter const& end) - noexcept { - if constexpr (has_conversions) { - using format_list = typename relaxed_conversions::type_list; - return relaxed_read_impl(itr, end); - } else { - // Fall back on strict policy - return detail::read(itr, end); - } - } - }; +}; } // namespace detail template class reader { public: - template using expected = detail::expected; - constexpr reader(std::span src) : - data(src), curr(std::begin(data)), end(std::end(data)) {} + constexpr reader(std::span src) + : data(src) + , curr(std::begin(data)) + , end(std::end(data)) {} template constexpr expected read() noexcept { if (curr == end) return tl::make_unexpected(error::end_of_message); - return detail::reader_policy_traits::template read(curr, end); + return detail::reader_policy_traits::template read( + curr, end); } - constexpr auto pos() const noexcept { - return curr; - } + constexpr auto pos() const noexcept { return curr; } constexpr auto subview() const noexcept { return std::span(curr, end); diff --git a/include/parselink/msgpack/core/writer.h b/include/parselink/msgpack/core/writer.h index deed9d0..245ad7e 100644 --- a/include/parselink/msgpack/core/writer.h +++ b/include/parselink/msgpack/core/writer.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -14,13 +14,13 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_core_writer_ce48a51aa6ed0858 #define msgpack_core_writer_ce48a51aa6ed0858 +#include "../util/endianness.h" #include "error.h" #include "format.h" -#include "../util/endianness.h" #include #include @@ -37,15 +37,15 @@ enum class writer_error { }; // Helper template for writing a non-integral datatype to an output. -//template -//struct write_adapter { - //template - //static constexpr tl::expected write(T const& t); +// template +// struct write_adapter { +// template +// static constexpr tl::expected write(T const& t); //}; template -constexpr inline decltype(auto) write_bytes(std::array&& data, - Itr out) noexcept { +constexpr inline decltype(auto) write_bytes( + std::array&& data, Itr out) noexcept { for (auto b : data) { *out++ = b; } @@ -57,9 +57,7 @@ struct write_adapter {}; template struct write_adapter { - static constexpr auto size(T) noexcept { - return sizeof(T); - } + static constexpr auto size(T) noexcept { return sizeof(T); } template static constexpr auto write(T t, Itr out) noexcept { @@ -75,7 +73,8 @@ struct write_adapter { template static constexpr auto write(std::string_view str, Itr out) noexcept { - std::byte const* beg = reinterpret_cast(&*str.begin()); + std::byte const* beg = + reinterpret_cast(&*str.begin()); std::copy(beg, beg + str.size(), out); return out += str.size(); } @@ -88,8 +87,8 @@ struct write_adapter> { } template - static constexpr auto write(std::span bytes, - Itr out) noexcept { + static constexpr auto write( + std::span bytes, Itr out) noexcept { std::copy(bytes.begin(), bytes.end(), out); return out += bytes.size(); } @@ -97,142 +96,137 @@ struct write_adapter> { template <> struct write_adapter { - static constexpr auto value(map_desc desc) noexcept { - return desc.count; - } + static constexpr auto value(map_desc desc) noexcept { return desc.count; } }; template <> struct write_adapter { - static constexpr auto value(array_desc desc) noexcept { - return desc.count; - } + static constexpr auto value(array_desc desc) noexcept { return desc.count; } }; // TODO: These could be optimized away because invalid/nil never contain real // data. template <> struct write_adapter { - static constexpr auto value(invalid) noexcept { - return 0; - } + static constexpr auto value(invalid) noexcept { return 0; } }; template <> struct write_adapter { - static constexpr auto value(nil) noexcept { - return 0; - } + static constexpr auto value(nil) noexcept { return 0; } }; namespace detail { - template - using expected = tl::expected; +template +using expected = tl::expected; - template - constexpr inline std::size_t calculate_space(typename F::value_type val) - noexcept { - // At a minimum, one byte is needed to store the format. - std::size_t size = sizeof(typename F::first_type); +template +constexpr inline std::size_t calculate_space( + typename F::value_type val) noexcept { + // At a minimum, one byte is needed to store the format. + std::size_t size = sizeof(typename F::first_type); - if (!is_fixtype) { - ++size; // For format - } - - if constexpr (F::payload_type == format::payload::variable) { - size += write_adapter::size(val); - } - - return size; + if (!is_fixtype) { + ++size; // For format } - // The "first type" is either the size of the variable length payload or - // a fixed-length value. Additionally, this "first type" may be inlined - // into the marker byte if it's a fix type. + if constexpr (F::payload_type == format::payload::variable) { + size += write_adapter::size(val); + } - template - constexpr inline expected pack_first( - typename F::value_type value) noexcept { - using value_type = typename F::value_type; - if constexpr (F::payload_type == format::payload::variable) { - return typename F::first_type(write_adapter::size(value)); + return size; +} + +// The "first type" is either the size of the variable length payload or +// a fixed-length value. Additionally, this "first type" may be inlined +// into the marker byte if it's a fix type. + +template +constexpr inline expected pack_first( + typename F::value_type value) noexcept { + using value_type = typename F::value_type; + if constexpr (F::payload_type == format::payload::variable) { + return typename F::first_type(write_adapter::size(value)); + } else { + if constexpr (requires { write_adapter::value; }) { + return typename F::first_type( + write_adapter::value(value)); } else { - if constexpr (requires { write_adapter::value; }) { - return typename F::first_type(write_adapter::value(value)); - } else { - return typename F::first_type(value); - } + return typename F::first_type(value); + } + } +} + +template +constexpr inline expected write( + typename F::value_type&& value, Itr out, Itr const end) { + using diff_type = typename std::iterator_traits::difference_type; + if (diff_type(calculate_space(value)) > std::distance(out, end)) { + return tl::make_unexpected(error::out_of_space); + } + + auto marker = F::marker; + + auto result = pack_first(value); + if (!result) { + return tl::make_unexpected(result.error()); + } + + if constexpr (is_fixtype) { + if (*result > 0xff) { + return tl::make_unexpected(error::bad_value); + } + if constexpr (F::flags & format::flag::apply_mask) { + marker |= std::byte(*result); + } else { + marker = std::byte(*result); + } + if ((marker & ~F::mask) != F::marker) { + return tl::make_unexpected(error::bad_value); } } - template - constexpr inline expected write( - typename F::value_type&& value, Itr out, Itr const end) { - using diff_type = typename std::iterator_traits::difference_type; - if (diff_type(calculate_space(value)) > std::distance(out, end)) { - return tl::make_unexpected(error::out_of_space); - } + *out++ = marker; - auto marker = F::marker; - - auto result = pack_first(value); - if (!result) { - return tl::make_unexpected(result.error()); - } - - if constexpr (is_fixtype) { - if (*result > 0xff) { - return tl::make_unexpected(error::bad_value); - } - if constexpr (F::flags & format::flag::apply_mask) { - marker |= std::byte(*result); - } else { - marker = std::byte(*result); - } - if ((marker & ~F::mask) != F::marker) { - return tl::make_unexpected(error::bad_value); - } - } - - *out++ = marker; - - if constexpr (!is_fixtype) { - out = write_adapter::write(*result, out); - } - - if constexpr (F::payload_type == format::payload::variable) { - out = write_adapter::write(value, out); - } - - return out; + if constexpr (!is_fixtype) { + out = write_adapter::write( + *result, out); } - template - struct format_hint; + if constexpr (F::payload_type == format::payload::variable) { + out = write_adapter::write(value, out); + } - template <> - struct format_hint { - using type = format::positive_fixint; - }; + return out; +} - template <> - struct format_hint { - using type = format::uint16; - }; +template +struct format_hint; + +template <> +struct format_hint { + using type = format::positive_fixint; +}; + +template <> +struct format_hint { + using type = format::uint16; +}; } // namespace detail class writer { public: - template using expected = detail::expected; - constexpr writer(std::span dest) : - data(dest), curr(std::begin(data)), end(std::end(data)) {} + constexpr writer(std::span dest) + : data(dest) + , curr(std::begin(data)) + , end(std::end(data)) {} template - constexpr expected write(typename F::value_type&& v) - noexcept { + constexpr expected write( + typename F::value_type&& v) noexcept { using value_type = typename F::value_type; if (curr == end) return tl::make_unexpected(error::out_of_space); auto result = detail::write(std::forward(v), curr, end); @@ -245,14 +239,12 @@ public: } template - requires requires { typename detail::format_hint::type; } + requires requires { typename detail::format_hint::type; } constexpr expected write(T&& v) { return write::type>(std::forward(v)); } - constexpr auto pos() const noexcept { - return curr; - } + constexpr auto pos() const noexcept { return curr; } constexpr auto tell() const noexcept { return std::distance(std::begin(data), curr); diff --git a/include/parselink/msgpack/token.h b/include/parselink/msgpack/token.h index 01e058f..e88e59e 100644 --- a/include/parselink/msgpack/token.h +++ b/include/parselink/msgpack/token.h @@ -1,8 +1,8 @@ #ifndef msgpack_object_f1f3a9e5c8be6a11 #define msgpack_object_f1f3a9e5c8be6a11 -#include "token/type.h" #include "token/reader.h" +#include "token/type.h" #include "token/views.h" #endif // msgpack_object_f1f3a9e5c8be6a11 diff --git a/include/parselink/msgpack/token/reader.h b/include/parselink/msgpack/token/reader.h index 8cc8f11..2d928df 100644 --- a/include/parselink/msgpack/token/reader.h +++ b/include/parselink/msgpack/token/reader.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -17,14 +17,14 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_token_reader_8daff350a0b1a519 #define msgpack_token_reader_8daff350a0b1a519 -#include "type.h" #include "../core/error.h" -#include "../util/endianness.h" #include "../core/format.h" +#include "../util/endianness.h" +#include "type.h" #include @@ -44,8 +44,7 @@ constexpr std::int64_t sign_extend(std::size_t size, auto bytes) noexcept { return {}; } -constexpr decltype(auto) read(std::size_t size, auto& inp) - noexcept { +constexpr decltype(auto) read(std::size_t size, auto& inp) noexcept { std::array value{}; be_to_host(inp, inp + size, std::begin(value)); inp += size; @@ -65,7 +64,7 @@ constexpr inline format::traits const& traits_lookup(std::byte id) { == format::negative_fixint::marker) { return format::get_traits(); } else if ((id & ~format::positive_fixint::mask) - == format::positive_fixint::marker) { + == format::positive_fixint::marker) { return format::get_traits(); } else if ((id & ~format::fixstr::mask) == format::fixstr::marker) { return format::get_traits(); @@ -76,8 +75,7 @@ constexpr inline format::traits const& traits_lookup(std::byte id) { } switch (id) { - case format::uint8::marker: - return format::get_traits(); + case format::uint8::marker: return format::get_traits(); case format::uint16::marker: return format::get_traits(); case format::uint32::marker: @@ -85,47 +83,33 @@ constexpr inline format::traits const& traits_lookup(std::byte id) { case format::uint64::marker: return format::get_traits(); - case format::int8::marker: - return format::get_traits(); - case format::int16::marker: - return format::get_traits(); - case format::int32::marker: - return format::get_traits(); - case format::int64::marker: - return format::get_traits(); + case format::int8::marker: return format::get_traits(); + case format::int16::marker: return format::get_traits(); + case format::int32::marker: return format::get_traits(); + case format::int64::marker: return format::get_traits(); - case format::str8::marker: - return format::get_traits(); - case format::str16::marker: - return format::get_traits(); - case format::str32::marker: - return format::get_traits(); - case format::bin8::marker: - return format::get_traits(); - case format::bin16::marker: - return format::get_traits(); - case format::bin32::marker: - return format::get_traits(); + case format::str8::marker: return format::get_traits(); + case format::str16::marker: return format::get_traits(); + case format::str32::marker: return format::get_traits(); + case format::bin8::marker: return format::get_traits(); + case format::bin16::marker: return format::get_traits(); + case format::bin32::marker: return format::get_traits(); case format::array16::marker: return format::get_traits(); case format::array32::marker: return format::get_traits(); - case format::map16::marker: - return format::get_traits(); - case format::map32::marker: - return format::get_traits(); + case format::map16::marker: return format::get_traits(); + case format::map32::marker: return format::get_traits(); - case format::nil::marker: - return format::get_traits(); + case format::nil::marker: return format::get_traits(); case format::invalid::marker: return format::get_traits(); case format::boolean::marker: case format::boolean::marker | std::byte{1}: return format::get_traits(); - default: - break; + default: break; } return format::no_traits; @@ -135,26 +119,22 @@ constexpr inline format::traits const& traits_lookup(std::byte id) { class token_reader { public: - - constexpr token_reader(std::span src) noexcept : - data_(src), curr_{} {} + constexpr token_reader(std::span src) noexcept + : data_(src) + , curr_{} {} constexpr auto current() const noexcept { return std::next(data_.begin(), curr_); } - constexpr auto end() const noexcept { - return data_.end(); - } + constexpr auto end() const noexcept { return data_.end(); } constexpr auto remaining(auto itr) noexcept { using dist_type = decltype(std::distance(itr, data_.end())); return std::max(dist_type(0), std::distance(itr, data_.end())); } - constexpr auto remaining() noexcept { - return remaining(current()); - } + constexpr auto remaining() noexcept { return remaining(current()); } // Read the next token. If the reader currently points to the end of the // byte buffer, then end_of_message is returned, and if there is still @@ -181,7 +161,7 @@ public: } // This is either the value of the format, or the size of the format. - auto first_bytes = [&]{ + auto first_bytes = [&] { if (traits.size) { return detail::read(traits.size, curr); } else { @@ -206,14 +186,11 @@ public: case format::type::boolean: tok = token{bool(first_bytes[0] & traits.mask)}; break; - case format::type::invalid: - tok = token{invalid{}}; - break; - case format::type::nil: - tok = token{nil{}}; - break; + case format::type::invalid: tok = token{invalid{}}; break; + case format::type::nil: tok = token{nil{}}; break; case format::type::unsigned_int: - tok = detail::make_token(first_bytes); + tok = detail::make_token( + first_bytes); break; case format::type::signed_int: { auto value = detail::sign_extend(traits.size, first_bytes); @@ -242,8 +219,7 @@ public: tok = token{map_desc(var_size)}; break; } - default: - return tl::make_unexpected(error::not_implemented); + default: return tl::make_unexpected(error::not_implemented); } curr_ = std::distance(data_.begin(), curr); @@ -261,9 +237,9 @@ public: error err = error::end_of_message; while (tok != token_buffer.end()) { - auto result = read_one().map([&tok](auto&& t){ - *tok = t; - ++tok; + auto result = read_one().map([&tok](auto&& t) { + *tok = t; + ++tok; }); if (!result) { err = result.error(); @@ -280,8 +256,7 @@ public: } template - constexpr tl::expected read() { - } + constexpr tl::expected read() {} private: std::span data_; diff --git a/include/parselink/msgpack/token/type.h b/include/parselink/msgpack/token/type.h index 50024f1..abafb49 100644 --- a/include/parselink/msgpack/token/type.h +++ b/include/parselink/msgpack/token/type.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -20,23 +20,22 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_token_type_f43c22522692063f #define msgpack_token_type_f43c22522692063f #include "../core/error.h" #include "../core/format.h" - -#include -#include - #include #include +#include #include #include #include #include +#include + namespace msgpack { // This API is _currently_ optimizing on the fact that most desktop/server @@ -54,7 +53,8 @@ namespace msgpack { // Of course, this means custom code! template -requires (sizeof(Size) + sizeof(std::underlying_type_t) <= sizeof(uintptr_t)) + requires(sizeof(Size) + sizeof(std::underlying_type_t) + <= sizeof(uintptr_t)) class size_and_enum { public: using size_type = Size; @@ -67,6 +67,7 @@ public: // Constructors constexpr size_and_enum() noexcept = default; + constexpr size_and_enum(size_type size, enum_type enum_value) noexcept { set_both(size, enum_value); } @@ -75,30 +76,34 @@ public: constexpr auto get_size() const noexcept { return static_cast((value & size_mask) >> size_shift); } + constexpr auto get_enum() const noexcept { return static_cast((value & enum_mask)); } + constexpr auto rep() const noexcept { return value; } // Mutators constexpr auto set_size(size_type size) noexcept { - value = (static_cast(size) << size_shift) | - (value & enum_mask); + value = (static_cast(size) << size_shift) + | (value & enum_mask); } + constexpr auto set_enum(enum_type enum_value) noexcept { - value = (static_cast(enum_value) & enum_mask) | - (value & size_mask); + value = (static_cast(enum_value) & enum_mask) + | (value & size_mask); } constexpr auto set_both(size_type size, enum_type enum_value) noexcept { - value = (static_cast(size) << size_shift) | - (static_cast(enum_value) & enum_mask); + value = (static_cast(size) << size_shift) + | (static_cast(enum_value) & enum_mask); } // Explicit conversion constexpr explicit operator size_type() const noexcept { return get_size(); } + constexpr explicit operator enum_type() const noexcept { return get_enum(); } @@ -156,9 +161,10 @@ class token_base<8> { public: constexpr static std::size_t word_size = 8; token_base() noexcept = default; + token_base(token_base const& other) noexcept - : value_(other.value_) - , size_and_type_(other.size_and_type_) {} + : value_(other.value_) + , size_and_type_(other.size_and_type_) {} template explicit token_base(T value) noexcept { @@ -215,11 +221,12 @@ public: template constexpr tl::expected get() const noexcept; - template + template constexpr tl::expected get() const noexcept { - constexpr auto expected_type = std::is_same_v ? - format::type::boolean : std::is_signed_v ? - format::type::signed_int : format::type::unsigned_int; + constexpr auto expected_type = + std::is_same_v ? format::type::boolean + : std::is_signed_v ? format::type::signed_int + : format::type::unsigned_int; if (type() != expected_type) { return tl::make_unexpected(error::wrong_type); @@ -227,8 +234,8 @@ public: if constexpr (expected_type == format::type::boolean) { return T(value_.b); } else if constexpr (expected_type == format::type::signed_int) { - if (std::numeric_limits::max() < value_.i || - std::numeric_limits::lowest() > value_.i) { + if (std::numeric_limits::max() < value_.i + || std::numeric_limits::lowest() > value_.i) { return tl::make_unexpected(error::will_truncate); } return T(value_.i); @@ -266,94 +273,82 @@ private: // TODO: What to store here for array/map types? Possibly a pointer // to the end of the array/map, if/when known? } value_; + size_and_enum size_and_type_{}; }; -template<> -inline tl::expected token_base<8>::get() - const noexcept -{ +template <> +inline tl::expected token_base<8>::get() const noexcept { if (type() != format::type::string) { return tl::make_unexpected(error::wrong_type); } return std::string{value_.str, size_and_type_.get_size()}; } -template<> -constexpr tl::expected token_base<8>::get() - const noexcept -{ +template <> +constexpr tl::expected +token_base<8>::get() const noexcept { if (type() != format::type::string) { return tl::make_unexpected(error::wrong_type); } return std::string_view{value_.str, size_and_type_.get_size()}; } - template - constexpr bool token_base<8>::operator==(char const (&t)[N]) const noexcept { - auto result = get().map([&t](auto v) { - return v == std::string_view{t}; }); - return result && *result; - } +template +constexpr bool token_base<8>::operator==(char const (&t)[N]) const noexcept { + auto result = get().map( + [&t](auto v) { return v == std::string_view{t}; }); + return result && *result; +} -template<> -inline tl::expected, error> token_base<8>::get() - const noexcept -{ +template <> +inline tl::expected, error> +token_base<8>::get() const noexcept { tl::expected, error> result; if (type() != format::type::binary) { result = tl::make_unexpected(error::wrong_type); } else { - result = std::vector(value_.bp, - value_.bp + size_and_type_.get_size()); + result = std::vector( + value_.bp, value_.bp + size_and_type_.get_size()); } return result; } -template<> +template <> constexpr tl::expected, error> -token_base<8>::get() const noexcept -{ +token_base<8>::get() const noexcept { if (type() != format::type::binary) { return tl::make_unexpected(error::wrong_type); } return std::span(value_.bp, size_and_type_.get_size()); } -template<> -constexpr tl::expected -token_base<8>::get() const noexcept -{ +template <> +constexpr tl::expected token_base<8>::get() const noexcept { if (type() != format::type::nil) { return tl::make_unexpected(error::wrong_type); } return nil{}; } -template<> -constexpr tl::expected -token_base<8>::get() const noexcept -{ +template <> +constexpr tl::expected token_base<8>::get() const noexcept { if (type() != format::type::invalid) { return tl::make_unexpected(error::wrong_type); } return invalid{}; } -template<> -constexpr tl::expected -token_base<8>::get() const noexcept -{ +template <> +constexpr tl::expected token_base<8>::get() const noexcept { if (type() != format::type::array) { return tl::make_unexpected(error::wrong_type); } return array_desc{size_and_type_.get_size()}; } -template<> -constexpr tl::expected -token_base<8>::get() const noexcept -{ +template <> +constexpr tl::expected token_base<8>::get() const noexcept { if (type() != format::type::map) { return tl::make_unexpected(error::wrong_type); } @@ -364,5 +359,4 @@ using token = token_base; } // namespace msgpack - #endif // msgpack_token_type_f43c22522692063f diff --git a/include/parselink/msgpack/token/views.h b/include/parselink/msgpack/token/views.h index 68267ad..4b550b7 100644 --- a/include/parselink/msgpack/token/views.h +++ b/include/parselink/msgpack/token/views.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -19,124 +19,119 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_token_views_f19c250e782ed51c #define msgpack_token_views_f19c250e782ed51c #include "type.h" - #include -#include #include +#include + namespace msgpack { - template - requires std::ranges::input_range && std::same_as> - struct map_view : public std::ranges::view_interface> { +template + requires std::ranges::input_range + && std::same_as> +struct map_view : public std::ranges::view_interface> { +public: + class sentinel; + + class iterator { + friend class sentinel; + + using base_iterator = std::ranges::iterator_t; + using base_sentinel = std::ranges::sentinel_t; + using base_value_type = std::ranges::range_value_t; + using base_reference = std::ranges::range_reference_t; + + base_iterator next(base_iterator current, std::size_t n = 1) { + while (n && current != std::ranges::end(*base_)) { + if (auto m = current->template get(); m) { + n += m->count * 2; + } else if (auto m = current->template get(); m) { + n += m->count; + } + ++current; + --n; + } + return current; + } + public: - class sentinel; + using value_type = std::pair; + using reference = std::pair; + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; - class iterator { - friend class sentinel; + iterator() = default; - using base_iterator = std::ranges::iterator_t; - using base_sentinel = std::ranges::sentinel_t; - using base_value_type = std::ranges::range_value_t; - using base_reference = std::ranges::range_reference_t; - - base_iterator next(base_iterator current, std::size_t n = 1) { - while (n && current != std::ranges::end(*base_)) { - if (auto m = current->template get(); m) { - n += m->count * 2; - } else if (auto m = current->template get(); m) { - n += m->count; - } - ++current; - --n; - } - return current; - } - - public: - using value_type = std::pair; - using reference = std::pair; - using difference_type = std::ptrdiff_t; - using iterator_category = std::input_iterator_tag; - - iterator() = default; - iterator(V const& base) - : base_{&base} - , k_{std::ranges::begin(base)} { - // Ensure that k_ points to a map_desc. If not, then we - // effectively treat this as the end. - if (k_->type() == msgpack::format::type::map) { - remaining_ = k_->template get()->count + 1; - // Advance to the first entry in the map. - ++k_; - v_ = next(k_); - } - } - - [[nodiscard]] reference operator*() const { - return { *k_, *v_ }; - } - - iterator& operator++() { - k_ = next(v_); + iterator(V const& base) + : base_{&base} + , k_{std::ranges::begin(base)} { + // Ensure that k_ points to a map_desc. If not, then we + // effectively treat this as the end. + if (k_->type() == msgpack::format::type::map) { + remaining_ = k_->template get()->count + 1; + // Advance to the first entry in the map. + ++k_; v_ = next(k_); - --remaining_; - return *this; } - - [[nodiscard]] iterator operator++(int) { - auto tmp = *this; - ++(*this); - return tmp; - } - - [[nodiscard]] bool operator==(iterator const& rhs) const { - return k_ == rhs.remaining_ && - base_ == rhs.base_; - } - - private: - V const* base_{}; - base_iterator k_{}; - base_iterator v_{}; - std::size_t remaining_{}; - }; - - class sentinel { - public: - [[nodiscard]] bool operator==(sentinel const&) const { - return true; - } - - [[nodiscard]] bool operator==(iterator const& rhs) const { - return rhs.remaining_ == 0 - || rhs.k_ == std::ranges::end(*rhs.base_); - } - }; - - constexpr map_view() noexcept = default; - constexpr map_view(V base) : base_{std::move(base)} {} - - [[nodiscard]] constexpr iterator begin() const { - return { base_ }; } - [[nodiscard]] constexpr sentinel end() const { - return {}; + + [[nodiscard]] reference operator*() const { return {*k_, *v_}; } + + iterator& operator++() { + k_ = next(v_); + v_ = next(k_); + --remaining_; + return *this; } + + [[nodiscard]] iterator operator++(int) { + auto tmp = *this; + ++(*this); + return tmp; + } + + [[nodiscard]] bool operator==(iterator const& rhs) const { + return k_ == rhs.remaining_ && base_ == rhs.base_; + } + private: - V base_; + V const* base_{}; + base_iterator k_{}; + base_iterator v_{}; + std::size_t remaining_{}; }; - template - map_view(Range&&) -> map_view>; + class sentinel { + public: + [[nodiscard]] bool operator==(sentinel const&) const { return true; } + + [[nodiscard]] bool operator==(iterator const& rhs) const { + return rhs.remaining_ == 0 + || rhs.k_ == std::ranges::end(*rhs.base_); + } + }; + + constexpr map_view() noexcept = default; + + constexpr map_view(V base) + : base_{std::move(base)} {} + + [[nodiscard]] constexpr iterator begin() const { return {base_}; } + + [[nodiscard]] constexpr sentinel end() const { return {}; } + +private: + V base_; +}; + +template +map_view(Range&&) -> map_view>; } // namespace msgpack - #endif // msgpack_token_views_f19c250e782ed51c diff --git a/include/parselink/msgpack/util/endianness.h b/include/parselink/msgpack/util/endianness.h index e7734bd..e265aa2 100644 --- a/include/parselink/msgpack/util/endianness.h +++ b/include/parselink/msgpack/util/endianness.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // @@ -15,7 +15,7 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef msgpack_endianness_d8ae54f45851ed13 #define msgpack_endianness_d8ae54f45851ed13 @@ -24,11 +24,7 @@ #include #include -enum class endianness { - big, - little, - other -}; +enum class endianness { big, little, other }; namespace detail { @@ -37,8 +33,8 @@ namespace detail { */ struct host_endianness_check { constexpr static inline std::uint32_t impl = 0x01020304; - constexpr static inline auto test = static_cast(impl); - constexpr static inline auto value = []{ + constexpr static inline auto test = static_cast(impl); + constexpr static inline auto value = [] { switch (test) { case 4: return endianness::little; case 1: return endianness::big; @@ -66,7 +62,7 @@ constexpr void byte_swap(Iter begin, Iter end, OutIter dest) { * byte_swap above should optimize to bswap or some equivalent assembly. */ template -requires (From != endianness::other && To != endianness::other) + requires(From != endianness::other && To != endianness::other) constexpr auto maybe_swap(std::array val) noexcept { if constexpr (From == To) { return val; @@ -78,7 +74,7 @@ constexpr auto maybe_swap(std::array val) noexcept { } template -requires (From != endianness::other && To != endianness::other) + requires(From != endianness::other && To != endianness::other) constexpr void maybe_swap_iter(Iter begin, Iter end, OutIter dest) noexcept { if constexpr (From == To) { std::copy(begin, end, dest); @@ -98,6 +94,7 @@ constexpr auto raw_cast(T val) noexcept { T val; std::array data; }; + trick_to_array u{val}; return u.data; } @@ -112,6 +109,7 @@ constexpr auto value_cast(Array&& data) noexcept { Array data; T val; }; + trick_to_value u{std::forward(data)}; return u.val; } @@ -120,14 +118,14 @@ constexpr auto value_cast(Array&& data) noexcept { * Byte swap implementation for arbitrary endiannesses. */ template -requires std::is_trivial_v> + requires std::is_trivial_v> constexpr T byte_swap(T val) noexcept { using array_type = std::array; return std::bit_cast( maybe_swap(std::bit_cast(val))); } -} // namespace detail; +} // namespace detail /** * Exposes endianness information about a target. diff --git a/include/parselink/proto/message.h b/include/parselink/proto/message.h index 2b5857b..843700b 100644 --- a/include/parselink/proto/message.h +++ b/include/parselink/proto/message.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Proto // @@ -14,16 +14,16 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef message_0c61530748b9f966 #define message_0c61530748b9f966 +#include #include #include -#include +#include #include -#include namespace parselink { namespace proto { @@ -38,8 +38,8 @@ namespace proto { // switch to something hand-crafted for saving bits. struct error_message { - std::uint32_t code; // An error code - std::string_view what; // A string + std::uint32_t code; // An error code + std::string_view what; // A string }; // C->S: Request to (re)connect. @@ -70,7 +70,7 @@ struct parser_data_message { std::span payload; }; -} // namespace message +} // namespace proto } // namespace parselink #endif // message_0c61530748b9f966 diff --git a/include/parselink/proto/session.h b/include/parselink/proto/session.h index 1a69c6e..76a2f82 100644 --- a/include/parselink/proto/session.h +++ b/include/parselink/proto/session.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Proto // @@ -14,18 +14,17 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef session_07eae057feface79 #define session_07eae057feface79 -#include - #include "parselink/msgpack/token.h" - #include #include #include +#include + namespace parselink { namespace proto { @@ -59,8 +58,8 @@ public: // the session is established or not. constexpr static std::uint32_t max_message_size = 128 * 1024; - std::string user_id; + private: }; @@ -68,4 +67,3 @@ private: } // namespace parselink #endif // session_0c61530748b9f966 - diff --git a/include/parselink/server.h b/include/parselink/server.h index 137ba76..9c6b04e 100644 --- a/include/parselink/server.h +++ b/include/parselink/server.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Server // @@ -14,12 +14,12 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef server_5b46f075be3caa00 #define server_5b46f075be3caa00 -#include #include +#include namespace parselink { diff --git a/include/parselink/utility/argparse.h b/include/parselink/utility/argparse.h index a41bf86..8dd26a8 100644 --- a/include/parselink/utility/argparse.h +++ b/include/parselink/utility/argparse.h @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Utility // @@ -15,16 +15,16 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #ifndef argparse_d2ddac0dab0d7b88 #define argparse_d2ddac0dab0d7b88 -#include #include +#include #include -#include #include +#include #include #include #include @@ -37,210 +37,205 @@ namespace argparse { - namespace custom { - template - struct argument_parser {}; +namespace custom { +template +struct argument_parser {}; - template - concept has_parser = requires { - { argument_parser>::parse(std::string_view{}) } - -> std::same_as; - }; - } +template +concept has_parser = requires { + { + argument_parser>::parse(std::string_view{}) + } -> std::same_as; +}; +} // namespace custom - template - struct argument_parser {}; +template +struct argument_parser {}; - template <> - struct argument_parser { - static bool* parse(std::string_view value) noexcept { - if (value == "1" || value == "true") { - return new bool{true}; - } else if (value == "0" || value == "false") { - return new bool{false}; - } - return nullptr; - } - }; - - inline constexpr std::initializer_list< - std::tuple> unit_map = { - {"ns", std::chrono::nanoseconds{1}}, - {"us", std::chrono::microseconds{1}}, - {"ms", std::chrono::milliseconds{1}}, - {"s", std::chrono::seconds{1}}, - {"m", std::chrono::minutes{1}}, - {"h", std::chrono::hours{1}}, - }; - - template - struct argument_parser> { - using duration = std::chrono::duration; - - static duration* parse(std::string_view value) noexcept { - rep result; - auto err = std::from_chars(value.begin(), value.end(), result); - if (err.ec == std::errc{}) { - auto this_unit = std::string_view{err.ptr, value.end()}; - for (auto const& [unit, dura] : unit_map) { - if (std::string_view{unit} == this_unit) { - auto v = - std::chrono::duration_cast(result * dura); - return new duration{v}; - } - } - } - - return nullptr; - } - }; - - template - requires requires (T& t) { - std::from_chars(nullptr, nullptr, t); - } - struct argument_parser { - static T* parse(std::string_view value) noexcept { - T result; - auto err = std::from_chars(value.begin(), value.end(), result); - return err.ec == std::errc{} ? new T{result} : nullptr; - } - }; - - template <> - struct argument_parser { - static std::string* parse(std::string_view value) noexcept { - return new std::string{value}; - } - }; - - template - concept has_parser = requires { - { argument_parser>::parse(std::string_view{}) } - -> std::same_as; - }; - - static_assert(has_parser); - -namespace detail { - - // This wrapper acts similar to std::any, but also provides a method to - // parse a string_view for the value as well. Parsers can be implemented - // by creating an argparse::custom::argument_parser template specialization - // for a given type. - struct any_arg { - - constexpr any_arg() = default; - - template - any_arg(T&& value) : iface(&dispatcher>::table) { - dispatcher>::create(*this, std::forward(value)); - } - - any_arg(any_arg const& other) : iface(other.iface) { - if (other.iface) { - data = other.iface->copy(other.data); - } - } - - any_arg(any_arg&& other) : data(std::move(other.data)), iface(other.iface) { - other.iface = nullptr; - } - - any_arg& operator=(any_arg const& other) { - if (has_value()) { - iface->destroy(data); - } - iface = other.iface; - if (other.iface) { - data = other.iface->copy(other.data); - } - return *this; - } - - ~any_arg() { - if (has_value()) { - iface->destroy(data); - } - } - - bool parse(std::string_view sv) { - return iface->parse(*this, sv); - } - - bool has_value() const noexcept { - return static_cast(iface); - } - - template - bool holds() const noexcept { - return iface == &dispatcher>::table; - } - - template - friend T const* arg_cast(any_arg const*) noexcept; - - void* data = nullptr; - struct interface { - void (*destroy)(void*); - void *(*copy)(void*); - bool (*parse)(any_arg&, std::string_view); - }; - - interface const* iface = nullptr; - - template - struct dispatcher { - template - static void create(any_arg& self, Args&&... args) { - self.data = new T{std::forward(args)...}; - } - - static void* copy(void *ptr) { - return new T{*static_cast(ptr)}; - } - - static bool parse(any_arg& self, std::string_view sv) { - if constexpr (custom::has_parser) { - self.data = custom::argument_parser::parse(sv); - return static_cast(self.data); - } else if constexpr (has_parser) { - self.data = argument_parser::parse(sv); - return static_cast(self.data); - } else { - return false; - } - } - - static void destroy(void* ptr) { - delete static_cast(ptr); - } - - static T const* cast(void* ptr) { - return static_cast(ptr); - } - - static constexpr struct interface table { - &dispatcher::destroy, &dispatcher::copy, &dispatcher::parse }; - }; - }; - - template - T const* arg_cast(any_arg const* ar) noexcept { - if (ar->holds()) { - return any_arg::dispatcher>::cast(ar->data); +template <> +struct argument_parser { + static bool* parse(std::string_view value) noexcept { + if (value == "1" || value == "true") { + return new bool{true}; + } else if (value == "0" || value == "false") { + return new bool{false}; } return nullptr; } +}; + +inline constexpr std::initializer_list< + std::tuple> + unit_map = { + {"ns", std::chrono::nanoseconds{1}}, + {"us", std::chrono::microseconds{1}}, + {"ms", std::chrono::milliseconds{1}}, + {"s", std::chrono::seconds{1}}, + {"m", std::chrono::minutes{1}}, + {"h", std::chrono::hours{1}}, +}; + +template +struct argument_parser> { + using duration = std::chrono::duration; + + static duration* parse(std::string_view value) noexcept { + rep result; + auto err = std::from_chars(value.begin(), value.end(), result); + if (err.ec == std::errc{}) { + auto this_unit = std::string_view{err.ptr, value.end()}; + for (auto const& [unit, dura] : unit_map) { + if (std::string_view{unit} == this_unit) { + auto v = + std::chrono::duration_cast(result * dura); + return new duration{v}; + } + } + } + + return nullptr; + } +}; + +template + requires requires(T& t) { std::from_chars(nullptr, nullptr, t); } +struct argument_parser { + static T* parse(std::string_view value) noexcept { + T result; + auto err = std::from_chars(value.begin(), value.end(), result); + return err.ec == std::errc{} ? new T{result} : nullptr; + } +}; + +template <> +struct argument_parser { + static std::string* parse(std::string_view value) noexcept { + return new std::string{value}; + } +}; + +template +concept has_parser = requires { + { + argument_parser>::parse(std::string_view{}) + } -> std::same_as; +}; + +static_assert(has_parser); + +namespace detail { + +// This wrapper acts similar to std::any, but also provides a method to +// parse a string_view for the value as well. Parsers can be implemented +// by creating an argparse::custom::argument_parser template specialization +// for a given type. +struct any_arg { + constexpr any_arg() = default; + + template + any_arg(T&& value) + : iface(&dispatcher>::table) { + dispatcher>::create(*this, std::forward(value)); + } + + any_arg(any_arg const& other) + : iface(other.iface) { + if (other.iface) { + data = other.iface->copy(other.data); + } + } + + any_arg(any_arg&& other) + : data(std::move(other.data)) + , iface(other.iface) { + other.iface = nullptr; + } + + any_arg& operator=(any_arg const& other) { + if (has_value()) { + iface->destroy(data); + } + iface = other.iface; + if (other.iface) { + data = other.iface->copy(other.data); + } + return *this; + } + + ~any_arg() { + if (has_value()) { + iface->destroy(data); + } + } + + bool parse(std::string_view sv) { return iface->parse(*this, sv); } + + bool has_value() const noexcept { return static_cast(iface); } + + template + bool holds() const noexcept { + return iface == &dispatcher>::table; + } + + template + friend T const* arg_cast(any_arg const*) noexcept; + + void* data = nullptr; + + struct interface { + void (*destroy)(void*); + void* (*copy)(void*); + bool (*parse)(any_arg&, std::string_view); + }; + + interface const* iface = nullptr; + + template + struct dispatcher { + template + static void create(any_arg& self, Args&&... args) { + self.data = new T{std::forward(args)...}; + } + + static void* copy(void* ptr) { return new T{*static_cast(ptr)}; } + + static bool parse(any_arg& self, std::string_view sv) { + if constexpr (custom::has_parser) { + self.data = custom::argument_parser::parse(sv); + return static_cast(self.data); + } else if constexpr (has_parser) { + self.data = argument_parser::parse(sv); + return static_cast(self.data); + } else { + return false; + } + } + + static void destroy(void* ptr) { delete static_cast(ptr); } + + static T const* cast(void* ptr) { return static_cast(ptr); } + + static constexpr struct interface table { + &dispatcher::destroy, &dispatcher::copy, &dispatcher::parse + }; + }; +}; + +template +T const* arg_cast(any_arg const* ar) noexcept { + if (ar->holds()) { + return any_arg::dispatcher>::cast(ar->data); + } + return nullptr; } +} // namespace detail class command_line_parser { public: - using argument = detail::any_arg; constexpr static char delimiter = '='; - using opt_list = std::initializer_list< - std::tuple>; + using opt_list = + std::initializer_list>; struct result { enum class code { @@ -261,8 +256,8 @@ public: template T const* maybe_opt(std::string_view name) const noexcept { auto entry = opts.find(name); - return entry != opts.end() ? - detail::arg_cast(&entry->second) : nullptr; + return entry != opts.end() ? detail::arg_cast(&entry->second) + : nullptr; } template @@ -306,7 +301,6 @@ public: } private: - static auto split_option(std::string_view kv) { auto delim = kv.find(delimiter); if (delim != kv.npos) { @@ -350,7 +344,6 @@ private: std::vector arguments_; }; -} - +} // namespace argparse #endif // argparse_d2ddac0dab0d7b88 diff --git a/source/logging/logging.cpp b/source/logging/logging.cpp index f3510ca..85f289a 100644 --- a/source/logging/logging.cpp +++ b/source/logging/logging.cpp @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // @@ -14,7 +14,7 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #include "parselink/logging.h" @@ -26,7 +26,7 @@ namespace { struct console_endpoint : public endpoint { static constexpr std::string_view format_string = - "{:%Y-%m-%d %H:%M:%S}.{:03} [{:<8}] {:>20} | {}\n"; + "{:%Y-%m-%d %H:%M:%S}.{:03} [{:<8}] {:>20} | {}\n"; bool colored() const noexcept override { return true; } @@ -38,23 +38,25 @@ struct console_endpoint : public endpoint { } }; -} +} // namespace auto& console() { static auto console = std::make_shared(); return console; } -logger::logger(std::string_view name) : name_{name} { +logger::logger(std::string_view name) + : name_{name} { endpoints_.emplace_back(console()); } -logger::logger(std::string_view name, std::vector> eps) - : name_{name}, endpoints_{std::move(eps)} {} +logger::logger( + std::string_view name, std::vector> eps) + : name_{name} + , endpoints_{std::move(eps)} {} void logger::set_threshold(level new_threshold) noexcept { for (auto& ep : endpoints_) { ep->threshold = new_threshold; } } - diff --git a/source/main.cpp b/source/main.cpp index e17e50d..e0da873 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,19 +1,19 @@ #include "parselink/logging.h" -#include #include +#include namespace { - parselink::logging::logger logger("main"); +parselink::logging::logger logger("main"); } using level = parselink::logging::level; int run(std::span arg_list) { argparse::command_line_parser parser({ - {"address", {std::string{"0.0.0.0"}}}, - {"user_port", {std::uint16_t{9001}}}, - {"websocket_port", {std::uint16_t{10501}}}, - {"verbose", {false}}, + {"address", {std::string{"0.0.0.0"}}}, + {"user_port", {std::uint16_t{9001}}}, + {"websocket_port", {std::uint16_t{10501}}}, + {"verbose", {false}}, }); auto args = parser.parse(arg_list); @@ -28,8 +28,6 @@ int run(std::span arg_list) { logger.set_threshold(level::trace); } - - auto server = parselink::make_server(args.opt("address"), args.opt("user_port"), args.opt("websocket_port")); @@ -41,8 +39,7 @@ int run(std::span arg_list) { return 0; } -int main(int argc, char* argv[]) -{ +int main(int argc, char* argv[]) { // TODO(ksassenrath): Add configuration file to the mix. std::vector args; diff --git a/source/proto/session.cpp b/source/proto/session.cpp index 822618a..3084f12 100644 --- a/source/proto/session.cpp +++ b/source/proto/session.cpp @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Server // @@ -16,15 +16,15 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #include "parselink/proto/session.h" -#include - #include "parselink/logging.h" #include "parselink/msgpack/token.h" +#include + using namespace parselink; using namespace parselink::proto; @@ -34,22 +34,27 @@ struct fmt::formatter { constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } - template + + template auto format(msgpack::token const& v, FormatContext& ctx) const { using parselink::logging::themed_arg; - auto out = fmt::format_to(ctx.out(), "()))); + fmt::format_to( + out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::signed_int: - out = fmt::format_to(out, "{}", themed_arg(*(v.get()))); + out = fmt::format_to( + out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::boolean: out = fmt::format_to(out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::string: - out = fmt::format_to(out, "{}", themed_arg(*(v.get()))); + out = fmt::format_to( + out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::binary: out = fmt::format_to(out, "{}", @@ -69,14 +74,12 @@ struct fmt::formatter { case msgpack::format::type::invalid: out = fmt::format_to(out, "(invalid)"); break; - default: - break; + default: break; } return fmt::format_to(out, ">"); } }; - namespace { logging::logger logger("session"); } @@ -91,7 +94,7 @@ tl::expected session::parse_header( } auto size = reader.read_one().and_then( - [](auto t){ return t.template get(); }); + [](auto t) { return t.template get(); }); if (!size || !*size) { logger.error("Failed to get valid message size"); @@ -133,13 +136,12 @@ tl::expected session::handle_connect( return tl::make_unexpected(error::bad_data); } if (k == "user_id") { - result = v.get().map([this](auto uid){ - user_id = std::move(uid); - }); + result = v.get().map( + [this](auto uid) { user_id = std::move(uid); }); } if (!result) { - logger.error("connect failed: {} -> {}: {}", k, v, - result.error()); + logger.error( + "connect failed: {} -> {}: {}", k, v, result.error()); return tl::make_unexpected(error::bad_data); } } diff --git a/source/server.cpp b/source/server.cpp index 69360fe..ee63191 100644 --- a/source/server.cpp +++ b/source/server.cpp @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Server // @@ -16,42 +16,38 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- -#include "parselink/logging.h" #include "parselink/server.h" +#include "parselink/logging.h" #include "parselink/msgpack/token/reader.h" #include "parselink/msgpack/token/views.h" #include "parselink/proto/session.h" - -#include - -#include -#include -#include -#include - -#include -#include - +#include #include #include #include -#include - +#include +#include +#include +#include +#include +#include #include #include +#include + using namespace parselink; using namespace std::chrono_literals; namespace net = boost::asio; -using net::co_spawn; using net::awaitable; -using net::use_awaitable; +using net::co_spawn; using net::deferred; using net::detached; +using net::use_awaitable; //----------------------------------------------------------------------------- // TODO(ksassenrath): These are logging formatters for various boost/asio types. @@ -65,7 +61,7 @@ struct parselink::logging::theme template <> struct fmt::formatter : fmt::formatter { - template + template constexpr auto format(auto const& v, FormatContext& ctx) const { return fmt::formatter::format(v.message(), ctx); } @@ -77,22 +73,27 @@ struct fmt::formatter { constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } - template + + template auto format(msgpack::token const& v, FormatContext& ctx) const { using parselink::logging::themed_arg; - auto out = fmt::format_to(ctx.out(), "()))); + fmt::format_to( + out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::signed_int: - out = fmt::format_to(out, "{}", themed_arg(*(v.get()))); + out = fmt::format_to( + out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::boolean: out = fmt::format_to(out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::string: - out = fmt::format_to(out, "{}", themed_arg(*(v.get()))); + out = fmt::format_to( + out, "{}", themed_arg(*(v.get()))); break; case msgpack::format::type::binary: out = fmt::format_to(out, "{}", @@ -112,8 +113,7 @@ struct fmt::formatter { case msgpack::format::type::invalid: out = fmt::format_to(out, "(invalid)"); break; - default: - break; + default: break; } return fmt::format_to(out, ">"); } @@ -121,8 +121,8 @@ struct fmt::formatter { template concept endpoint = requires(T const& t) { - {t.address()}; - {t.port()}; + { t.address() }; + { t.port() }; }; template @@ -130,12 +130,11 @@ struct parselink::logging::theme : parselink::logging::static_theme {}; template -struct fmt::formatter - : fmt::formatter { - template +struct fmt::formatter : fmt::formatter { + template constexpr auto format(auto const& v, FormatContext& ctx) const { - return fmt::format_to(ctx.out(), "{}:{}", v.address().to_string(), - v.port()); + return fmt::format_to( + ctx.out(), "{}:{}", v.address().to_string(), v.port()); } }; @@ -144,10 +143,10 @@ struct fmt::formatter //----------------------------------------------------------------------------- namespace { - logging::logger logger("server"); - constexpr auto no_ex_coro = net::as_tuple(use_awaitable); - constexpr auto no_ex_defer = net::as_tuple(deferred); -} +logging::logger logger("server"); +constexpr auto no_ex_coro = net::as_tuple(use_awaitable); +constexpr auto no_ex_defer = net::as_tuple(deferred); +} // namespace struct user_session { std::string user_id; @@ -163,7 +162,6 @@ public: std::error_code run() noexcept override; private: - friend user_session; awaitable user_listen(); @@ -181,8 +179,8 @@ private: class user_connection : public std::enable_shared_from_this { public: user_connection(monolithic_server& server, net::ip::tcp::socket sock) - : server_(server) - , socket_(std::move(sock)) {} + : server_(server) + , socket_(std::move(sock)) {} ~user_connection() { logger.debug("Connection to {} closed.", socket_.remote_endpoint()); @@ -193,17 +191,17 @@ public: void start() { logger.debug("New connection from {}", socket_.remote_endpoint()); - co_spawn(socket_.get_executor(), [self = shared_from_this()]{ - return self->await_connect(); - }, detached); + co_spawn( + socket_.get_executor(), + [self = shared_from_this()] { return self->await_connect(); }, + detached); } tl::expected, msgpack::error> parse_header( std::span data) noexcept { auto reader = msgpack::token_reader(data); - auto magic = reader.read_one().map( - [](auto t){ return t == "prs"; }); + auto magic = reader.read_one().map([](auto t) { return t == "prs"; }); if (magic && *magic) { logger.debug("Got magic from client"); } else { @@ -212,7 +210,7 @@ public: } auto sz = reader.read_one().and_then( - [](auto t){ return t.template get(); }); + [](auto t) { return t.template get(); }); if (sz && *sz) { logger.debug("Got packet size from client: {}", *sz); } else { @@ -231,7 +229,6 @@ public: awaitable> buffer_message(std::span buffer) noexcept { - std::size_t amt = 0; while (amt < buffer.size()) { @@ -276,12 +273,11 @@ public: // Copy remaining portion of message in initial read to the message // buffer. - std::copy( - std::next(buffer.begin(), maybe_hdr->bytes_read), - std::next(buffer.begin(), n), - msg.begin()); + std::copy(std::next(buffer.begin(), maybe_hdr->bytes_read), + std::next(buffer.begin(), n), msg.begin()); - auto msg_span = std::span(msg.begin() + n - maybe_hdr->bytes_read, msg.end()); + auto msg_span = + std::span(msg.begin() + n - maybe_hdr->bytes_read, msg.end()); if (auto result = co_await buffer_message(msg_span); !result) { logger.error("Unable to parse header: {}", result.error()); @@ -301,14 +297,10 @@ public: // Authenticate against database. logger.debug("User {} established connection", session.user_id); - //session_ = server_.establish_session(std::move(*maybe_user)); + // session_ = server_.establish_session(std::move(*maybe_user)); } - enum class state { - init, - authenticated, - active - }; + enum class state { init, authenticated, active }; monolithic_server& server_; user_session* session_{}; @@ -322,15 +314,17 @@ monolithic_server::monolithic_server(std::string_view address, , user_port_{user_port} , websocket_port_{websocket_port} { logger.debug("Creating monolithic_server(address = {}, user_port = {}, " - "websocket_port = {})", address, user_port_, websocket_port_); + "websocket_port = {})", + address, user_port_, websocket_port_); } awaitable monolithic_server::user_listen() { auto exec = co_await net::this_coro::executor; net::ip::tcp::acceptor acceptor{exec, {addr_, user_port_}}; while (true) { - std::make_shared(*this, - co_await acceptor.async_accept(use_awaitable))->start(); + std::make_shared( + *this, co_await acceptor.async_accept(use_awaitable)) + ->start(); } } @@ -338,7 +332,7 @@ std::error_code monolithic_server::run() noexcept { logger.info("Starting server."); net::signal_set signals(io_context_, SIGINT, SIGTERM); - signals.async_wait([&](auto, auto){ + signals.async_wait([&](auto, auto) { logger.info("Received signal... Shutting down."); io_context_.stop(); }); @@ -354,8 +348,8 @@ user_session* monolithic_server::establish_session(user_session session) { auto existing_session = active_user_sessions_.find(session.user_id); if (existing_session == active_user_sessions_.end()) { // No session exists with that user ID yet. - active_user_sessions_.emplace(session.user_id, - std::move(session.user_id)); + active_user_sessions_.emplace( + session.user_id, std::move(session.user_id)); } return {}; } diff --git a/tests/logging/logging.cpp b/tests/logging/logging.cpp index 67e5bc9..9f65a42 100644 --- a/tests/logging/logging.cpp +++ b/tests/logging/logging.cpp @@ -1,11 +1,11 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Tests // @@ -14,7 +14,7 @@ // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- #include "parselink/logging.h" @@ -32,16 +32,18 @@ struct test_endpoint_base : public endpoint { void write(message const& msg) override { if constexpr (Colored) { buffer_.append(fmt::format("{} {} | {}", - themed_arg{enum_name_only{msg.lvl}}, msg.name, msg.message)); + themed_arg{enum_name_only{msg.lvl}}, msg.name, + msg.message)); } else { - buffer_.append(fmt::format("{} {} | {}", - enum_name_only{msg.lvl}, msg.name, msg.message)); + buffer_.append(fmt::format("{} {} | {}", enum_name_only{msg.lvl}, + msg.name, msg.message)); } } bool colored() const noexcept override { return Colored; } void clear() { buffer_.clear(); } + std::string_view contents() const { return buffer_; } std::string buffer_; @@ -58,15 +60,19 @@ using colored_test_endpoint = test_endpoint_base; // In order to test themed (colorized) logging, we must be sure that theming // gets correctly-styled content. -struct static_theme_test { int value; }; +struct static_theme_test { + int value; +}; // In order to test themed (colorized) logging, we must be sure that theming // gets correctly-styled content. -struct dynamic_theme_test { int value; }; +struct dynamic_theme_test { + int value; +}; template auto styled(T&& v) { - if constexpr(has_static_theme) { + if constexpr (has_static_theme) { return fmt::styled(v, theme>::style); } else if constexpr (has_dynamic_theme) { return fmt::styled(v, theme>::style(v)); @@ -75,7 +81,7 @@ auto styled(T&& v) { } } -} +} // namespace template <> struct fmt::formatter : public fmt::formatter { @@ -104,7 +110,6 @@ struct parselink::logging::theme { } }; - // Begin tests! using namespace boost::ut; @@ -226,18 +231,18 @@ suite logging = [] { { auto const& cptrref = ptr; logger.log("int const pointer&: {}", cptrref); - auto expected = fmt::format( - "info formatting | int const pointer&: {}", - fmt::ptr(cptrref)); + auto expected = + fmt::format("info formatting | int const pointer&: {}", + fmt::ptr(cptrref)); expect(ep->contents() == expected); ep->clear(); } { logger.log("std::unique_ptr: {}", uniq_ptr); - auto expected = fmt::format( - "info formatting | std::unique_ptr: {}", - fmt::ptr(uniq_ptr)); + auto expected = + fmt::format("info formatting | std::unique_ptr: {}", + fmt::ptr(uniq_ptr)); expect(ep->contents() == expected); ep->clear(); } @@ -245,17 +250,17 @@ suite logging = [] { { auto& uniq_ptrref = uniq_ptr; logger.log("std::unique_ptr&: {}", uniq_ptrref); - auto expected = fmt::format( - "info formatting | std::unique_ptr&: {}", - fmt::ptr(uniq_ptrref)); + auto expected = + fmt::format("info formatting | std::unique_ptr&: {}", + fmt::ptr(uniq_ptrref)); expect(ep->contents() == expected); ep->clear(); } { auto const& cuniq_ptrref = uniq_ptr; - logger.log("std::unique_ptr const&: {}", - cuniq_ptrref); + logger.log( + "std::unique_ptr const&: {}", cuniq_ptrref); auto expected = fmt::format( "info formatting | std::unique_ptr const&: {}", fmt::ptr(cuniq_ptrref)); @@ -265,9 +270,9 @@ suite logging = [] { { logger.log("std::shared_ptr: {}", shr_ptr); - auto expected = fmt::format( - "info formatting | std::shared_ptr: {}", - fmt::ptr(shr_ptr)); + auto expected = + fmt::format("info formatting | std::shared_ptr: {}", + fmt::ptr(shr_ptr)); expect(ep->contents() == expected); ep->clear(); } @@ -275,17 +280,17 @@ suite logging = [] { { auto& shr_ptrref = shr_ptr; logger.log("std::shared_ptr&: {}", shr_ptrref); - auto expected = fmt::format( - "info formatting | std::shared_ptr&: {}", - fmt::ptr(shr_ptrref)); + auto expected = + fmt::format("info formatting | std::shared_ptr&: {}", + fmt::ptr(shr_ptrref)); expect(ep->contents() == expected); ep->clear(); } { auto const& cshr_ptrref = shr_ptr; - logger.log("std::shared_ptr const&: {}", - cshr_ptrref); + logger.log( + "std::shared_ptr const&: {}", cshr_ptrref); auto expected = fmt::format( "info formatting | std::shared_ptr const&: {}", fmt::ptr(cshr_ptrref)); @@ -330,8 +335,8 @@ suite logging = [] { dynamic_theme_test red{21}, green{202}; auto formatted = fmt::format("{}", styled(stt)); - auto expected = fmt::format("{}", - fmt::styled(stt.value, fmt::fg(fmt::color::black))); + auto expected = fmt::format( + "{}", fmt::styled(stt.value, fmt::fg(fmt::color::black))); expect(formatted == expected); formatted = fmt::format("{}", themed_arg{stt}); expect(formatted == expected); @@ -351,8 +356,8 @@ suite logging = [] { auto [logger, ep] = make_test_logger("colored"); logger.log(""); - auto expected = fmt::format("{} colored | ", - styled(enum_name_only{level::info})); + auto expected = fmt::format( + "{} colored | ", styled(enum_name_only{level::info})); expect(ep->contents() == expected); ep->clear(); @@ -387,12 +392,11 @@ suite logging = [] { auto* int_ptr = &int_value; logger.log("pointer {} {}", int_ptr, *int_ptr); expected = fmt::format("{} colored | pointer {} {}", - styled(enum_name_only{level::info}), - themed_arg{int_ptr}, themed_arg{*int_ptr}); + styled(enum_name_only{level::info}), themed_arg{int_ptr}, + themed_arg{*int_ptr}); expect(ep->contents() == expected); ep->clear(); }; }; -int main(int, char**) { -} +int main(int, char**) {} diff --git a/tests/msgpack/rng.h b/tests/msgpack/rng.h index 239d7d4..986dc75 100644 --- a/tests/msgpack/rng.h +++ b/tests/msgpack/rng.h @@ -5,16 +5,23 @@ #include struct rng { - rng(auto s) : seed(s), generator(seed) {} - rng() : rng([]{ return std::random_device{}(); }()) {} + rng(auto s) + : seed(s) + , generator(seed) {} + + rng() + : rng([] { return std::random_device{}(); }()) {} template - requires std::is_integral_v + requires std::is_integral_v T get() noexcept { union { - std::array data; + std::array + data; T v; } u; + for (auto& d : u.data) { d = generator(); } @@ -23,7 +30,7 @@ struct rng { } template - requires std::is_integral_v + requires std::is_integral_v auto get() noexcept { std::array values; for (auto& value : values) { diff --git a/tests/msgpack/test_reader_relaxed.cpp b/tests/msgpack/test_reader_relaxed.cpp index dd6b58a..0a02315 100644 --- a/tests/msgpack/test_reader_relaxed.cpp +++ b/tests/msgpack/test_reader_relaxed.cpp @@ -1,7 +1,5 @@ #include "parselink/msgpack/core/reader.h" - #include - #include namespace { @@ -10,55 +8,56 @@ using namespace boost::ut; namespace format = msgpack::format; template -constexpr std::array make_bytes(Bytes &&...bytes) { - return {std::byte(std::forward(bytes))...}; +constexpr std::array make_bytes(Bytes&&... bytes) { + return {std::byte(std::forward(bytes))...}; } -template struct oversized_array { - std::array data; - std::size_t size; +template +struct oversized_array { + std::array data; + std::size_t size; }; -constexpr auto to_bytes_array_oversized(auto const &container) { - oversized_array arr; - std::copy(std::begin(container), std::end(container), std::begin(arr.data)); - arr.size = std::distance(std::begin(container), std::end(container)); - return arr; +constexpr auto to_bytes_array_oversized(auto const& container) { + oversized_array arr; + std::copy(std::begin(container), std::end(container), std::begin(arr.data)); + arr.size = std::distance(std::begin(container), std::end(container)); + return arr; } consteval auto generate_bytes(auto callable) { - constexpr auto oversized = to_bytes_array_oversized(callable()); - std::array out; - std::copy(std::begin(oversized.data), + constexpr auto oversized = to_bytes_array_oversized(callable()); + std::array out; + std::copy(std::begin(oversized.data), std::next(std::begin(oversized.data), oversized.size), std::begin(out)); - return out; + return out; } template -consteval auto cat(std::array const &a, - std::array const &b) { - std::array out; - std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), +consteval auto cat( + std::array const& a, std::array const& b) { + std::array out; + std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), std::begin(out)); - std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), + std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), std::next(std::begin(out), std::size(a))); - return out; + return out; } template constexpr auto zip(T val, Itr begin, Itr end) { - std::vector output; - for (auto itr = begin; itr != end; ++itr) { - output.emplace_back(val); - output.emplace_back(*itr); - } - return output; + std::vector output; + for (auto itr = begin; itr != end; ++itr) { + output.emplace_back(val); + output.emplace_back(*itr); + } + return output; } template -constexpr auto zip(T val, Iterable const &itr) { - return zip(val, std::begin(itr), std::end(itr)); +constexpr auto zip(T val, Iterable const& itr) { + return zip(val, std::begin(itr), std::end(itr)); } using relaxed_reader = msgpack::reader; @@ -66,65 +65,65 @@ using relaxed_reader = msgpack::reader; } // namespace suite relaxed = [] { - "empty span"_test = [] { - using error = msgpack::error; - std::span bytes; - relaxed_reader reader(bytes); - auto v = reader.read(); - expect(v.error() == error::end_of_message); - }; + "empty span"_test = [] { + using error = msgpack::error; + std::span bytes; + relaxed_reader reader(bytes); + auto v = reader.read(); + expect(v.error() == error::end_of_message); + }; -//////////////////////////////////////////////////////////////////////////////// -// Unsigned integers -//////////////////////////////////////////////////////////////////////////////// - "reader::read"_test = [] { - using fmt = format::uint8; - using error = msgpack::error; - /** - * All bytes 0x00->0x79 are effectively literal uint8s. - */ - { - constexpr auto payload = make_bytes(0x52, 0xcc, 0x84); - relaxed_reader reader(payload); - { - auto result = reader.read(); - expect(result == std::uint8_t(0x52)); - } - { - auto result = reader.read(); - expect(result == std::uint8_t(0x84)); - } + //////////////////////////////////////////////////////////////////////////////// + // Unsigned integers + //////////////////////////////////////////////////////////////////////////////// + "reader::read"_test = [] { + using fmt = format::uint8; + using error = msgpack::error; + /** + * All bytes 0x00->0x79 are effectively literal uint8s. + */ + { + constexpr auto payload = make_bytes(0x52, 0xcc, 0x84); + relaxed_reader reader(payload); + { + auto result = reader.read(); + expect(result == std::uint8_t(0x52)); + } + { + auto result = reader.read(); + expect(result == std::uint8_t(0x84)); + } - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - }; + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + }; - "reader::read"_test = [] { - using fmt = msgpack::format::uint16; - using error = msgpack::error; - /** - * All bytes 0x00->0x79 are effectively literal uint8s. - */ - { - constexpr auto payload = make_bytes(0x52, 0xcc, 0x84, 0xcd, 0xaa, 0xcc); - relaxed_reader reader(payload); - { - auto result = reader.read(); - expect(result == std::uint16_t(0x52)); - } - { - auto result = reader.read(); - expect(result == std::uint16_t(0x84)); - } - { - auto result = reader.read(); - expect(result == std::uint16_t(0xaacc)); - } + "reader::read"_test = [] { + using fmt = msgpack::format::uint16; + using error = msgpack::error; + /** + * All bytes 0x00->0x79 are effectively literal uint8s. + */ + { + constexpr auto payload = + make_bytes(0x52, 0xcc, 0x84, 0xcd, 0xaa, 0xcc); + relaxed_reader reader(payload); + { + auto result = reader.read(); + expect(result == std::uint16_t(0x52)); + } + { + auto result = reader.read(); + expect(result == std::uint16_t(0x84)); + } + { + auto result = reader.read(); + expect(result == std::uint16_t(0xaacc)); + } - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - }; + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + }; }; - diff --git a/tests/msgpack/test_reader_strict.cpp b/tests/msgpack/test_reader_strict.cpp index 9cb7d56..db9a106 100644 --- a/tests/msgpack/test_reader_strict.cpp +++ b/tests/msgpack/test_reader_strict.cpp @@ -1,707 +1,709 @@ #include "parselink/msgpack/core/reader.h" #include "rng.h" - #include - #include namespace { constexpr static std::size_t rng_samples_count = 10; -template constexpr auto enum_name() noexcept { - return __PRETTY_FUNCTION__; +template +constexpr auto enum_name() noexcept { + return __PRETTY_FUNCTION__; } using namespace boost::ut; namespace format = msgpack::format; template -constexpr std::array make_bytes(Bytes &&...bytes) { - return {std::byte(std::forward(bytes))...}; +constexpr std::array make_bytes(Bytes&&... bytes) { + return {std::byte(std::forward(bytes))...}; } -template struct oversized_array { - std::array data; - std::size_t size; +template +struct oversized_array { + std::array data; + std::size_t size; }; -constexpr auto to_bytes_array_oversized(auto const &container) { - oversized_array arr; - std::copy(std::begin(container), std::end(container), std::begin(arr.data)); - arr.size = std::distance(std::begin(container), std::end(container)); - return arr; +constexpr auto to_bytes_array_oversized(auto const& container) { + oversized_array arr; + std::copy(std::begin(container), std::end(container), std::begin(arr.data)); + arr.size = std::distance(std::begin(container), std::end(container)); + return arr; } consteval auto generate_bytes(auto callable) { - constexpr auto oversized = to_bytes_array_oversized(callable()); - std::array out; - std::copy(std::begin(oversized.data), + constexpr auto oversized = to_bytes_array_oversized(callable()); + std::array out; + std::copy(std::begin(oversized.data), std::next(std::begin(oversized.data), oversized.size), std::begin(out)); - return out; + return out; } template -consteval auto cat(std::array const &a, - std::array const &b) { - std::array out; - std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), +consteval auto cat( + std::array const& a, std::array const& b) { + std::array out; + std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), std::begin(out)); - std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), + std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), std::next(std::begin(out), std::size(a))); - return out; + return out; } template constexpr auto zip(T val, Itr begin, Itr end) { - std::vector output; - for (auto itr = begin; itr != end; ++itr) { - output.emplace_back(val); - output.emplace_back(*itr); - } - return output; + std::vector output; + for (auto itr = begin; itr != end; ++itr) { + output.emplace_back(val); + output.emplace_back(*itr); + } + return output; } template -constexpr auto zip(T val, Iterable const &itr) { - return zip(val, std::begin(itr), std::end(itr)); +constexpr auto zip(T val, Iterable const& itr) { + return zip(val, std::begin(itr), std::end(itr)); } constexpr auto from_string_view(std::string_view sv) { - std::vector range; - range.resize(sv.size()); - auto itr = range.begin(); - for (auto c : sv) { - *itr = std::byte(c); - ++itr; - } - return range; + std::vector range; + range.resize(sv.size()); + auto itr = range.begin(); + for (auto c : sv) { + *itr = std::byte(c); + ++itr; + } + return range; } constexpr auto make_contiguous_range(std::uint8_t start, std::uint8_t end) { - auto count = std::size_t(end) - std::size_t(start) + 1; - std::vector range; - range.resize(count); - for (auto i = std::size_t(start); i <= std::size_t(end); ++i) { - range[i - std::size_t(start)] = std::byte(i); - } - return range; + auto count = std::size_t(end) - std::size_t(start) + 1; + std::vector range; + range.resize(count); + for (auto i = std::size_t(start); i <= std::size_t(end); ++i) { + range[i - std::size_t(start)] = std::byte(i); + } + return range; } } // namespace suite reader = [] { - "empty span"_test = [] { - std::span bytes; - msgpack::reader reader(bytes); - auto v = reader.read(); - expect(v.error() == msgpack::error::end_of_message); - }; + "empty span"_test = [] { + std::span bytes; + msgpack::reader reader(bytes); + auto v = reader.read(); + expect(v.error() == msgpack::error::end_of_message); + }; - //////////////////////////////////////////////////////////////////////////////// - // Unsigned integers - //////////////////////////////////////////////////////////////////////////////// - "reader::read"_test = [] { - using fmt = format::positive_fixint; - using error = msgpack::error; - /** - * All bytes 0x00->0x79 are effectively literal uint8s. - */ - { - constexpr auto payload = - generate_bytes([] { return make_contiguous_range(0, 0x79); }); - msgpack::reader reader(payload); - static_assert( - std::is_same_v())::value_type, std::uint8_t>); - for (auto byte : payload) { - auto result = reader.read(); - expect(result == std::uint8_t(byte)); - } + //////////////////////////////////////////////////////////////////////////////// + // Unsigned integers + //////////////////////////////////////////////////////////////////////////////// + "reader::read"_test = [] { + using fmt = format::positive_fixint; + using error = msgpack::error; + /** + * All bytes 0x00->0x79 are effectively literal uint8s. + */ + { + constexpr auto payload = generate_bytes( + [] { return make_contiguous_range(0, 0x79); }); + msgpack::reader reader(payload); + static_assert(std::is_same_v< + typename decltype(reader.read())::value_type, + std::uint8_t>); + for (auto byte : payload) { + auto result = reader.read(); + expect(result == std::uint8_t(byte)); + } - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - { - constexpr auto payload = - generate_bytes([] { return make_contiguous_range(0x80, 0xff); }); - // Continually narrow the span over the range, as read will not - // advance the internal span on failure. - for (auto itr = payload.begin(); itr != payload.end(); ++itr) { - msgpack::reader reader(std::span(itr, std::end(payload))); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::wrong_type)); - } - } - }; - - "reader::read"_test = [] { - using fmt = format::uint8; - using error = msgpack::error; - /** - * The uint8 format is 0xcc followed by one byte of data. - */ - { - constexpr auto payload = generate_bytes([] { - return zip(std::byte{0xcc}, make_contiguous_range(0x00, 0xff)); - }); - msgpack::reader reader(payload); - static_assert( - std::is_same_v())::value_type, std::uint8_t>); - for (auto i = 0; i < 0x100; ++i) { - auto result = reader.read(); - expect(result == std::uint8_t(i)); - } - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - { - using error = msgpack::error; - // Test that partial read fails. - constexpr auto payload = make_bytes(0xcc); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - // Retry, ensure the error remains the same. - result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - }; - - "reader::read"_test = [] { - using fmt = format::uint16; - using error = msgpack::error; - rng rng; - { - auto samples = rng.get(); - std::vector payload; - for (auto sample : samples) { - auto bytes = ::detail::raw_cast(host_to_be(sample)); - payload.push_back(std::byte{0xcd}); - for (auto byte : bytes) { - payload.push_back(byte); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); } - } - - msgpack::reader reader(payload); - for (auto sample : samples) { - auto result = reader.read(); - expect(result == sample); - } - - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - - { - constexpr auto payload = make_bytes(0xee); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::wrong_type)); - } - - // Test that partial read fails. - { - constexpr auto payload = make_bytes(0xcd); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - constexpr auto payload2 = make_bytes(0xcd, 0x01); - reader = msgpack::reader(payload2); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - }; - - "reader::read"_test = [] { - using fmt = format::uint32; - using error = msgpack::error; - rng rng; - auto samples = rng.get(); - std::vector payload; - for (auto sample : samples) { - auto bytes = ::detail::raw_cast(host_to_be(sample)); - payload.push_back(std::byte{0xce}); - for (auto byte : bytes) { - payload.push_back(byte); - } - } - - msgpack::reader reader(payload); - for (auto sample : samples) { - auto result = reader.read(); - expect(bool(result)); - expect(result == sample); - } - // Test that partial read fails. - { - constexpr auto payload = make_bytes(0xce, 0x01, 0x02, 0x03, 0x09); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == 0x01020309); - } - }; - - "reader::read"_test = [] { - using fmt = format::uint64; - using error = msgpack::error; - rng rng; - auto samples = rng.get(); - std::vector payload; - for (auto sample : samples) { - auto bytes = ::detail::raw_cast(host_to_be(sample)); - payload.push_back(std::byte{0xcf}); - for (auto byte : bytes) { - payload.push_back(byte); - } - } - - msgpack::reader reader(payload); - for (auto sample : samples) { - auto result = reader.read(); - expect(bool(result)); - expect(result == sample); - } - - { - constexpr auto payload = - make_bytes(0xcf, 0x01, 0x02, 0x03, 0x09, 0x10, 0x20, 0x30, 0x90); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == 0x0102030910203090); - } - }; - - //////////////////////////////////////////////////////////////////////////////// - // Signed integers - //////////////////////////////////////////////////////////////////////////////// - "reader::read"_test = [] { - using fmt = format::negative_fixint; - using error = msgpack::error; - /** - * All bytes 0x00->0x79 are effectively literal uint8s. - */ - { - constexpr auto payload = - generate_bytes([] { return make_contiguous_range(0xe0, 0xff); }); - msgpack::reader reader(payload); - static_assert( - std::is_same_v())::value_type, std::int8_t>); - for (auto byte : payload) { - auto result = reader.read(); - expect(result == std::int8_t(byte)); - } - - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - { - constexpr auto payload = - generate_bytes([] { return make_contiguous_range(0x00, 0xdf); }); - // Continually narrow the span over the range, as read will not - // advance the internal span on failure. - for (auto itr = payload.begin(); itr != payload.end(); ++itr) { - msgpack::reader reader(std::span(itr, std::end(payload))); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::wrong_type)); - } - } - }; - - "reader::read"_test = [] { - using fmt = format::int8; - using error = msgpack::error; - /** - * The uint8 format is 0xcc followed by one byte of data. - */ - { - constexpr auto payload = generate_bytes([] { - return zip(std::byte{0xd0}, make_contiguous_range(0x00, 0xff)); - }); - msgpack::reader reader(payload); - static_assert( - std::is_same_v())::value_type, std::int8_t>); - for (auto i = 0; i < 0x100; ++i) { - auto result = reader.read(); - expect(*result == std::int8_t(i)); - } - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } - { - using error = msgpack::error; - // Test that partial read fails. - constexpr auto payload = make_bytes(0xd0); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - // Retry, ensure the error remains the same. - result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - }; - - "reader::read"_test = [] { - using fmt = format::int16; - using error = msgpack::error; - rng rng; - { - auto samples = rng.get(); - std::vector payload; - for (auto sample : samples) { - auto bytes = ::detail::raw_cast(host_to_be(sample)); - payload.push_back(std::byte{0xd1}); - for (auto byte : bytes) { - payload.push_back(byte); + { + constexpr auto payload = generate_bytes( + [] { return make_contiguous_range(0x80, 0xff); }); + // Continually narrow the span over the range, as read will not + // advance the internal span on failure. + for (auto itr = payload.begin(); itr != payload.end(); ++itr) { + msgpack::reader reader(std::span(itr, std::end(payload))); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::wrong_type)); + } } - } + }; - msgpack::reader reader(payload); - for (auto sample : samples) { + "reader::read"_test = [] { + using fmt = format::uint8; + using error = msgpack::error; + /** + * The uint8 format is 0xcc followed by one byte of data. + */ + { + constexpr auto payload = generate_bytes([] { + return zip(std::byte{0xcc}, make_contiguous_range(0x00, 0xff)); + }); + msgpack::reader reader(payload); + static_assert(std::is_same_v< + typename decltype(reader.read())::value_type, + std::uint8_t>); + for (auto i = 0; i < 0x100; ++i) { + auto result = reader.read(); + expect(result == std::uint8_t(i)); + } + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + { + using error = msgpack::error; + // Test that partial read fails. + constexpr auto payload = make_bytes(0xcc); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + // Retry, ensure the error remains the same. + result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } + }; + + "reader::read"_test = [] { + using fmt = format::uint16; + using error = msgpack::error; + rng rng; + { + auto samples = rng.get(); + std::vector payload; + for (auto sample : samples) { + auto bytes = ::detail::raw_cast(host_to_be(sample)); + payload.push_back(std::byte{0xcd}); + for (auto byte : bytes) { + payload.push_back(byte); + } + } + + msgpack::reader reader(payload); + for (auto sample : samples) { + auto result = reader.read(); + expect(result == sample); + } + + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + + { + constexpr auto payload = make_bytes(0xee); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::wrong_type)); + } + + // Test that partial read fails. + { + constexpr auto payload = make_bytes(0xcd); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + constexpr auto payload2 = make_bytes(0xcd, 0x01); + reader = msgpack::reader(payload2); + expect(result == tl::make_unexpected(error::incomplete_message)); + } + }; + + "reader::read"_test = [] { + using fmt = format::uint32; + using error = msgpack::error; + rng rng; + auto samples = rng.get(); + std::vector payload; + for (auto sample : samples) { + auto bytes = ::detail::raw_cast(host_to_be(sample)); + payload.push_back(std::byte{0xce}); + for (auto byte : bytes) { + payload.push_back(byte); + } + } + + msgpack::reader reader(payload); + for (auto sample : samples) { + auto result = reader.read(); + expect(bool(result)); + expect(result == sample); + } + // Test that partial read fails. + { + constexpr auto payload = make_bytes(0xce, 0x01, 0x02, 0x03, 0x09); + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result + == tl::make_unexpected(error::incomplete_message)); + } + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == 0x01020309); + } + }; + + "reader::read"_test = [] { + using fmt = format::uint64; + using error = msgpack::error; + rng rng; + auto samples = rng.get(); + std::vector payload; + for (auto sample : samples) { + auto bytes = ::detail::raw_cast(host_to_be(sample)); + payload.push_back(std::byte{0xcf}); + for (auto byte : bytes) { + payload.push_back(byte); + } + } + + msgpack::reader reader(payload); + for (auto sample : samples) { + auto result = reader.read(); + expect(bool(result)); + expect(result == sample); + } + + { + constexpr auto payload = make_bytes( + 0xcf, 0x01, 0x02, 0x03, 0x09, 0x10, 0x20, 0x30, 0x90); + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result + == tl::make_unexpected(error::incomplete_message)); + } + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == 0x0102030910203090); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + // Signed integers + //////////////////////////////////////////////////////////////////////////////// + "reader::read"_test = [] { + using fmt = format::negative_fixint; + using error = msgpack::error; + /** + * All bytes 0x00->0x79 are effectively literal uint8s. + */ + { + constexpr auto payload = generate_bytes( + [] { return make_contiguous_range(0xe0, 0xff); }); + msgpack::reader reader(payload); + static_assert(std::is_same_v< + typename decltype(reader.read())::value_type, + std::int8_t>); + for (auto byte : payload) { + auto result = reader.read(); + expect(result == std::int8_t(byte)); + } + + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + { + constexpr auto payload = generate_bytes( + [] { return make_contiguous_range(0x00, 0xdf); }); + // Continually narrow the span over the range, as read will not + // advance the internal span on failure. + for (auto itr = payload.begin(); itr != payload.end(); ++itr) { + msgpack::reader reader(std::span(itr, std::end(payload))); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::wrong_type)); + } + } + }; + + "reader::read"_test = [] { + using fmt = format::int8; + using error = msgpack::error; + /** + * The uint8 format is 0xcc followed by one byte of data. + */ + { + constexpr auto payload = generate_bytes([] { + return zip(std::byte{0xd0}, make_contiguous_range(0x00, 0xff)); + }); + msgpack::reader reader(payload); + static_assert(std::is_same_v< + typename decltype(reader.read())::value_type, + std::int8_t>); + for (auto i = 0; i < 0x100; ++i) { + auto result = reader.read(); + expect(*result == std::int8_t(i)); + } + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + { + using error = msgpack::error; + // Test that partial read fails. + constexpr auto payload = make_bytes(0xd0); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + // Retry, ensure the error remains the same. + result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } + }; + + "reader::read"_test = [] { + using fmt = format::int16; + using error = msgpack::error; + rng rng; + { + auto samples = rng.get(); + std::vector payload; + for (auto sample : samples) { + auto bytes = ::detail::raw_cast(host_to_be(sample)); + payload.push_back(std::byte{0xd1}); + for (auto byte : bytes) { + payload.push_back(byte); + } + } + + msgpack::reader reader(payload); + for (auto sample : samples) { + auto result = reader.read(); + expect(result == sample); + } + + auto result = reader.read(); + expect(result == tl::make_unexpected(error::end_of_message)); + } + + { + constexpr auto payload = make_bytes(0xd2); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::wrong_type)); + } + + // Test that partial read fails. + { + constexpr auto payload = make_bytes(0xd1); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + constexpr auto payload2 = make_bytes(0xd1, 0x01); + reader = msgpack::reader(payload2); + expect(result == tl::make_unexpected(error::incomplete_message)); + } + }; + + "reader::read"_test = [] { + using fmt = format::int32; + using error = msgpack::error; + rng rng; + auto samples = rng.get(); + std::vector payload; + for (auto sample : samples) { + auto bytes = ::detail::raw_cast(host_to_be(sample)); + payload.push_back(std::byte{0xd2}); + for (auto byte : bytes) { + payload.push_back(byte); + } + } + + msgpack::reader reader(payload); + for (auto sample : samples) { + auto result = reader.read(); + expect(bool(result)); + expect(result == sample); + } + // Test that partial read fails. + { + constexpr auto payload = make_bytes(0xd2, 0xff, 0xff, 0xff, 0xfe); + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result + == tl::make_unexpected(error::incomplete_message)); + } + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == -2); + } + }; + + "reader::read"_test = [] { + using fmt = format::int64; + using error = msgpack::error; + rng rng; + auto samples = rng.get(); + std::vector payload; + for (auto sample : samples) { + auto bytes = ::detail::raw_cast(host_to_be(sample)); + payload.push_back(std::byte{0xd3}); + for (auto byte : bytes) { + payload.push_back(byte); + } + } + + msgpack::reader reader(payload); + for (auto sample : samples) { + auto result = reader.read(); + expect(bool(result)); + expect(result == sample); + } + + { + constexpr auto payload = make_bytes( + 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0); + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result + == tl::make_unexpected(error::incomplete_message)); + } + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == -16); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + // Strings + //////////////////////////////////////////////////////////////////////////////// + + "reader::read"_test = [] { + using fmt = msgpack::format::fixstr; + using error = msgpack::error; + constexpr std::string_view sv = "hello"; + constexpr auto payload = cat(make_bytes(0xa0 + sv.size()), + generate_bytes([sv] { return from_string_view(sv); })); + + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } + + msgpack::reader reader(payload); auto result = reader.read(); - expect(result == sample); - } + expect(result == sv); + }; - auto result = reader.read(); - expect(result == tl::make_unexpected(error::end_of_message)); - } + "reader::read"_test = [] { + using fmt = msgpack::format::str8; + using error = msgpack::error; + constexpr std::string_view sv = "hello d"; + constexpr auto payload = cat(make_bytes(0xd9, sv.size()), + generate_bytes([sv] { return from_string_view(sv); })); - { - constexpr auto payload = make_bytes(0xd2); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::wrong_type)); - } + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } - // Test that partial read fails. - { - constexpr auto payload = make_bytes(0xd1); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - constexpr auto payload2 = make_bytes(0xd1, 0x01); - reader = msgpack::reader(payload2); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - }; - - "reader::read"_test = [] { - using fmt = format::int32; - using error = msgpack::error; - rng rng; - auto samples = rng.get(); - std::vector payload; - for (auto sample : samples) { - auto bytes = ::detail::raw_cast(host_to_be(sample)); - payload.push_back(std::byte{0xd2}); - for (auto byte : bytes) { - payload.push_back(byte); - } - } - - msgpack::reader reader(payload); - for (auto sample : samples) { - auto result = reader.read(); - expect(bool(result)); - expect(result == sample); - } - // Test that partial read fails. - { - constexpr auto payload = make_bytes(0xd2, 0xff, 0xff, 0xff, 0xfe); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); + msgpack::reader reader(payload); auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == -2); - } - }; + expect(result == sv); + }; - "reader::read"_test = [] { - using fmt = format::int64; - using error = msgpack::error; - rng rng; - auto samples = rng.get(); - std::vector payload; - for (auto sample : samples) { - auto bytes = ::detail::raw_cast(host_to_be(sample)); - payload.push_back(std::byte{0xd3}); - for (auto byte : bytes) { - payload.push_back(byte); - } - } + "reader::read"_test = [] { + using fmt = msgpack::format::str16; + using error = msgpack::error; + constexpr std::string_view sv = "hello world"; + constexpr auto payload = cat(make_bytes(0xda, 0x00, sv.size()), + generate_bytes([sv] { return from_string_view(sv); })); - msgpack::reader reader(payload); - for (auto sample : samples) { - auto result = reader.read(); - expect(bool(result)); - expect(result == sample); - } + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } - { - constexpr auto payload = - make_bytes(0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); + msgpack::reader reader(payload); auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == -16); - } - }; + expect(result == sv); + }; - //////////////////////////////////////////////////////////////////////////////// - // Strings - //////////////////////////////////////////////////////////////////////////////// + "reader::read"_test = [] { + using fmt = msgpack::format::str32; + using error = msgpack::error; + constexpr std::string_view sv = "hello world"; + constexpr auto payload = + cat(make_bytes(0xdb, 0x00, 0x00, 0x00, sv.size()), + generate_bytes([sv] { return from_string_view(sv); })); - "reader::read"_test = [] { - using fmt = msgpack::format::fixstr; - using error = msgpack::error; - constexpr std::string_view sv = "hello"; - constexpr auto payload = - cat(make_bytes(0xa0 + sv.size()), - generate_bytes([sv] { return from_string_view(sv); })); + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == sv); + }; - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == sv); - }; + //////////////////////////////////////////////////////////////////////////////// + // Binary payloads + //////////////////////////////////////////////////////////////////////////////// - "reader::read"_test = [] { - using fmt = msgpack::format::str8; - using error = msgpack::error; - constexpr std::string_view sv = "hello d"; - constexpr auto payload = - cat(make_bytes(0xd9, sv.size()), - generate_bytes([sv] { return from_string_view(sv); })); + "reader::read"_test = [] { + using fmt = msgpack::format::bin8; + using error = msgpack::error; + constexpr auto bv = make_bytes(0x0, 0x01, 0x02, 0x04); + constexpr auto payload = cat(make_bytes(0xc4, bv.size()), bv); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == sv); - }; + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result.has_value()); + expect(std::equal( + (*result).begin(), (*result).end(), bv.begin(), bv.end())); + }; - "reader::read"_test = [] { - using fmt = msgpack::format::str16; - using error = msgpack::error; - constexpr std::string_view sv = "hello world"; - constexpr auto payload = - cat(make_bytes(0xda, 0x00, sv.size()), - generate_bytes([sv] { return from_string_view(sv); })); + "reader::read"_test = [] { + using fmt = msgpack::format::bin16; + using error = msgpack::error; + constexpr auto bv = generate_bytes([] { + auto rg = make_contiguous_range(0, 0xff); + std::vector rg2(rg.size() * 2); + auto itr = std::copy(rg.begin(), rg.end(), rg2.begin()); + std::copy(rg.begin(), rg.end(), itr); + return rg2; + }); + constexpr auto payload = + cat(make_bytes(0xc5, bv.size() >> 8, bv.size() & 0xff), bv); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == sv); - }; + msgpack::reader reader(payload); + auto result = reader.read(); + expect(std::equal( + (*result).begin(), (*result).end(), bv.begin(), bv.end())); + }; - "reader::read"_test = [] { - using fmt = msgpack::format::str32; - using error = msgpack::error; - constexpr std::string_view sv = "hello world"; - constexpr auto payload = - cat(make_bytes(0xdb, 0x00, 0x00, 0x00, sv.size()), - generate_bytes([sv] { return from_string_view(sv); })); + // TODO: Support this with a proper test payload + "reader::read"_test = [] { + using fmt = msgpack::format::bin32; + using error = msgpack::error; + constexpr auto bv = generate_bytes([] { + auto rg = make_contiguous_range(0, 0xff); + std::vector rg2(rg.size() * 2); + auto itr = std::copy(rg.begin(), rg.end(), rg2.begin()); + std::copy(rg.begin(), rg.end(), itr); + return rg2; + }); + constexpr auto payload = + cat(make_bytes(0xc6, bv.size() >> 24, bv.size() >> 16, + bv.size() >> 8, bv.size() & 0xff), + bv); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { + msgpack::reader reader({payload.begin(), itr}); + auto result = reader.read(); + expect(result == tl::make_unexpected(error::incomplete_message)); + } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == sv); - }; + msgpack::reader reader(payload); + auto result = reader.read(); + expect(std::equal( + (*result).begin(), (*result).end(), bv.begin(), bv.end())); + }; - //////////////////////////////////////////////////////////////////////////////// - // Binary payloads - //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + // Misc formats + //////////////////////////////////////////////////////////////////////////////// + "reader::read"_test = [] { + using fmt = msgpack::format::nil; + constexpr auto payload = make_bytes(0xc0); - "reader::read"_test = [] { - using fmt = msgpack::format::bin8; - using error = msgpack::error; - constexpr auto bv = make_bytes(0x0, 0x01, 0x02, 0x04); - constexpr auto payload = cat(make_bytes(0xc4, bv.size()), bv); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result.has_value()); + }; - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + "reader::read"_test = [] { + using fmt = msgpack::format::boolean; + constexpr auto payload = make_bytes(0xc2, 0xc3); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == false); + result = reader.read(); + expect(result == true); + }; - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result.has_value()); - expect( - std::equal((*result).begin(), (*result).end(), bv.begin(), bv.end())); - }; + //////////////////////////////////////////////////////////////////////////////// + // Structural formats + //////////////////////////////////////////////////////////////////////////////// + "reader::read"_test = [] { + using fmt = msgpack::format::fixarray; + using error = msgpack::error; + // A MessagePack array of 5 8-bit unsigned integers. + constexpr auto payload = make_bytes(0x95, 0xcc, 0x85, 0xcc, 0x84, 0xcc, + 0x83, 0xcc, 0x82, 0xcc, 0x81); - "reader::read"_test = [] { - using fmt = msgpack::format::bin16; - using error = msgpack::error; - constexpr auto bv = generate_bytes([] { - auto rg = make_contiguous_range(0, 0xff); - std::vector rg2(rg.size() * 2); - auto itr = std::copy(rg.begin(), rg.end(), rg2.begin()); - std::copy(rg.begin(), rg.end(), itr); - return rg2; - }); - constexpr auto payload = - cat(make_bytes(0xc5, bv.size() >> 8, bv.size() & 0xff), bv); + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == msgpack::array_desc{5}); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + for (std::size_t i = 0; i < (*result).count; ++i) { + auto v = reader.read(); + expect(v == 0x85 - i); + } - msgpack::reader reader(payload); - auto result = reader.read(); - expect( - std::equal((*result).begin(), (*result).end(), bv.begin(), bv.end())); - }; + auto end = reader.read(); + expect(end == tl::make_unexpected(error::end_of_message)); + }; - // TODO: Support this with a proper test payload - "reader::read"_test = [] { - using fmt = msgpack::format::bin32; - using error = msgpack::error; - constexpr auto bv = generate_bytes([] { - auto rg = make_contiguous_range(0, 0xff); - std::vector rg2(rg.size() * 2); - auto itr = std::copy(rg.begin(), rg.end(), rg2.begin()); - std::copy(rg.begin(), rg.end(), itr); - return rg2; - }); - constexpr auto payload = - cat(make_bytes(0xc6, bv.size() >> 24, bv.size() >> 16, bv.size() >> 8, - bv.size() & 0xff), - bv); + "reader::read"_test = [] { + using fmt = msgpack::format::array16; + using error = msgpack::error; + // A MessagePack array of 5 8-bit unsigned integers. + constexpr auto payload = make_bytes(0xdc, 0x00, 0x05, 0xcc, 0x85, 0xcc, + 0x84, 0xcc, 0x83, 0xcc, 0x82, 0xcc, 0x81); - for (auto itr = payload.begin() + 1; itr != payload.end(); ++itr) { - msgpack::reader reader({payload.begin(), itr}); - auto result = reader.read(); - expect(result == tl::make_unexpected(error::incomplete_message)); - } + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == msgpack::array_desc{5}); - msgpack::reader reader(payload); - auto result = reader.read(); - expect( - std::equal((*result).begin(), (*result).end(), bv.begin(), bv.end())); - }; + for (std::size_t i = 0; i < (*result).count; ++i) { + auto v = reader.read(); + expect(v == 0x85 - i); + } - //////////////////////////////////////////////////////////////////////////////// - // Misc formats - //////////////////////////////////////////////////////////////////////////////// - "reader::read"_test = [] { - using fmt = msgpack::format::nil; - constexpr auto payload = make_bytes(0xc0); + auto end = reader.read(); + expect(end == tl::make_unexpected(error::end_of_message)); + }; - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result.has_value()); - }; + "reader::read"_test = [] { + using fmt = msgpack::format::array32; + using error = msgpack::error; + // A MessagePack array of 5 8-bit unsigned integers. + constexpr auto payload = make_bytes(0xdd, 0x00, 0x00, 0x00, 0x05, 0xcc, + 0x85, 0xcc, 0x84, 0xcc, 0x83, 0xcc, 0x82, 0xcc, 0x81); - "reader::read"_test = [] { - using fmt = msgpack::format::boolean; - constexpr auto payload = make_bytes(0xc2, 0xc3); - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == false); - result = reader.read(); - expect(result == true); - }; + msgpack::reader reader(payload); + auto result = reader.read(); + expect(result == msgpack::array_desc{5}); - //////////////////////////////////////////////////////////////////////////////// - // Structural formats - //////////////////////////////////////////////////////////////////////////////// - "reader::read"_test = [] { - using fmt = msgpack::format::fixarray; - using error = msgpack::error; - // A MessagePack array of 5 8-bit unsigned integers. - constexpr auto payload = make_bytes(0x95, 0xcc, 0x85, 0xcc, 0x84, 0xcc, - 0x83, 0xcc, 0x82, 0xcc, 0x81); + for (std::size_t i = 0; i < (*result).count; ++i) { + auto v = reader.read(); + expect(v == 0x85 - i); + } - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == msgpack::array_desc{5}); - - for (std::size_t i = 0; i < (*result).count; ++i) { - auto v = reader.read(); - expect(v == 0x85 - i); - } - - auto end = reader.read(); - expect(end == tl::make_unexpected(error::end_of_message)); - }; - - "reader::read"_test = [] { - using fmt = msgpack::format::array16; - using error = msgpack::error; - // A MessagePack array of 5 8-bit unsigned integers. - constexpr auto payload = - make_bytes(0xdc, 0x00, 0x05, 0xcc, 0x85, 0xcc, 0x84, 0xcc, 0x83, 0xcc, - 0x82, 0xcc, 0x81); - - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == msgpack::array_desc{5}); - - for (std::size_t i = 0; i < (*result).count; ++i) { - auto v = reader.read(); - expect(v == 0x85 - i); - } - - auto end = reader.read(); - expect(end == tl::make_unexpected(error::end_of_message)); - }; - - "reader::read"_test = [] { - using fmt = msgpack::format::array32; - using error = msgpack::error; - // A MessagePack array of 5 8-bit unsigned integers. - constexpr auto payload = - make_bytes(0xdd, 0x00, 0x00, 0x00, 0x05, 0xcc, 0x85, 0xcc, 0x84, 0xcc, - 0x83, 0xcc, 0x82, 0xcc, 0x81); - - msgpack::reader reader(payload); - auto result = reader.read(); - expect(result == msgpack::array_desc{5}); - - for (std::size_t i = 0; i < (*result).count; ++i) { - auto v = reader.read(); - expect(v == 0x85 - i); - } - - auto end = reader.read(); - expect(end == tl::make_unexpected(error::end_of_message)); - }; + auto end = reader.read(); + expect(end == tl::make_unexpected(error::end_of_message)); + }; }; - diff --git a/tests/msgpack/test_speed.cpp b/tests/msgpack/test_speed.cpp index 44fdf17..83219cc 100644 --- a/tests/msgpack/test_speed.cpp +++ b/tests/msgpack/test_speed.cpp @@ -1,15 +1,15 @@ #include "parselink/msgpack/token.h" -//#include "parselink/proto/message.h" - -#include -#include -#include +// #include "parselink/proto/message.h" #include #include #include +#include #include +#include +#include + using namespace std::chrono_literals; struct any { @@ -37,7 +37,6 @@ auto read_file(char const* filename) { } int main(int argc, char** argv) { - std::array buf; auto data = read_file(argc < 2 ? "output.bin" : argv[1]); @@ -47,42 +46,48 @@ int main(int argc, char** argv) { auto before = std::chrono::steady_clock::now(); auto test = reader.read_some(buf); auto after = std::chrono::steady_clock::now(); - test.map([&](auto sp){ - fmt::print("Read {} tokens\n", sp.size()); - for (auto token : sp) { - fmt::print("token type: {} value: ", magic_enum::enum_name(token.type())); - switch (token.type()) { - case msgpack::format::type::unsigned_int: - fmt::print("{}", *(token.template get())); - break; - case msgpack::format::type::signed_int: - fmt::print("{}", *(token.template get())); - break; - case msgpack::format::type::boolean: - fmt::print("{}", *(token.template get())); - break; - case msgpack::format::type::string: - fmt::print("{}", *(token.template get())); - break; - case msgpack::format::type::binary: - fmt::print("{}", *(token.template get>())); - break; - case msgpack::format::type::map: - fmt::print("map ({} entries)", token.template get()->count); - break; - case msgpack::format::type::array: - fmt::print("array ({} entries)", token.template get()->count); - break; - case msgpack::format::type::nil: - fmt::print("(nil)"); - break; - case msgpack::format::type::invalid: - fmt::print("(invalid)"); - break; + test.map([&](auto sp) { + fmt::print("Read {} tokens\n", sp.size()); + for (auto token : sp) { + fmt::print("token type: {} value: ", + magic_enum::enum_name(token.type())); + switch (token.type()) { + case msgpack::format::type::unsigned_int: + fmt::print( + "{}", *(token.template get())); + break; + case msgpack::format::type::signed_int: + fmt::print("{}", *(token.template get())); + break; + case msgpack::format::type::boolean: + fmt::print("{}", *(token.template get())); + break; + case msgpack::format::type::string: + fmt::print("{}", + *(token.template get())); + break; + case msgpack::format::type::binary: + fmt::print( + "{}", *(token.template get< + std::span>())); + break; + case msgpack::format::type::map: + fmt::print("map ({} entries)", + token.template get()->count); + break; + case msgpack::format::type::array: + fmt::print("array ({} entries)", + token.template get() + ->count); + break; + case msgpack::format::type::nil: fmt::print("(nil)"); break; + case msgpack::format::type::invalid: + fmt::print("(invalid)"); + break; + } + fmt::print("\n"); } - fmt::print("\n"); - } - }).map_error([&](auto err){ + }).map_error([&](auto err) { fmt::print("Failed to read tokens: {}\n", (int)err); }); fmt::print("Took {} us\n", (after - before) / 1us); diff --git a/tests/msgpack/test_token.cpp b/tests/msgpack/test_token.cpp index 2d3ee02..9c4e777 100644 --- a/tests/msgpack/test_token.cpp +++ b/tests/msgpack/test_token.cpp @@ -1,40 +1,37 @@ #include "parselink/msgpack/token.h" - #include using namespace boost::ut; namespace { - template - constexpr std::array make_bytes(Bytes &&...bytes) { - return {std::byte(std::forward(bytes))...}; - } +template +constexpr std::array make_bytes(Bytes&&... bytes) { + return {std::byte(std::forward(bytes))...}; +} - template - constexpr bool wrong_types(auto const& obj) { - auto err = tl::make_unexpected(msgpack::error::wrong_type); - if (obj.template get() != err) return false; - if constexpr (sizeof...(Others)) { - return wrong_types(obj); - } else { - return true; - } - } - - template - std::ostream &operator<<(std::ostream &os, tl::expected const &exp) { - if (exp.has_value()) { - os << "Value: '" << *exp << "'"; - } else { - os << "Error"; - } - return os; +template +constexpr bool wrong_types(auto const& obj) { + auto err = tl::make_unexpected(msgpack::error::wrong_type); + if (obj.template get() != err) return false; + if constexpr (sizeof...(Others)) { + return wrong_types(obj); + } else { + return true; } } -enum class foo : std::uint8_t { - a, b, c, d, e -}; +template +std::ostream& operator<<(std::ostream& os, tl::expected const& exp) { + if (exp.has_value()) { + os << "Value: '" << *exp << "'"; + } else { + os << "Error"; + } + return os; +} +} // namespace + +enum class foo : std::uint8_t { a, b, c, d, e }; suite size_and_enum = [] { "expected use case"_test = [] { @@ -118,18 +115,19 @@ suite assignment_and_access = [] { std::vector extracted_val; { auto val = make_bytes(0x32, 0xff, 0xaa, 0xce); - msgpack::token obj(val); expect(obj.type() == msgpack::format::type::binary); + msgpack::token obj(val); + expect(obj.type() == msgpack::format::type::binary); auto retrieved = obj.get>(); expect(bool(retrieved)); - expect(std::equal(retrieved->begin(), retrieved->end(), - val.begin(), val.end())); + expect(std::equal(retrieved->begin(), retrieved->end(), val.begin(), + val.end())); expect(wrong_types(obj)); auto bytes_retrieved = obj.get>(); expect(bool(bytes_retrieved)); extracted_val = std::move(*bytes_retrieved); } expect(std::equal(expected_val.begin(), expected_val.end(), - extracted_val.begin(), extracted_val.end())); + extracted_val.begin(), extracted_val.end())); }; }; diff --git a/tests/msgpack/test_token_reader.cpp b/tests/msgpack/test_token_reader.cpp index 88a4e7e..8b56711 100644 --- a/tests/msgpack/test_token_reader.cpp +++ b/tests/msgpack/test_token_reader.cpp @@ -1,8 +1,8 @@ +#include +#include #include -#include #include -#include using namespace boost::ut; @@ -18,17 +18,17 @@ constexpr std::array as_bytes(T&& t) { } template -constexpr std::array make_bytes(Bytes &&...bytes) { +constexpr std::array make_bytes(Bytes&&... bytes) { return {std::byte(std::forward(bytes))...}; } -template struct oversized_array { +template +struct oversized_array { std::array data; std::size_t size; }; - -constexpr auto to_bytes_array_oversized(auto const &container) { +constexpr auto to_bytes_array_oversized(auto const& container) { using value_type = std::decay_t; oversized_array arr; std::copy(std::begin(container), std::end(container), std::begin(arr.data)); @@ -51,8 +51,8 @@ consteval auto build_string(auto callable) { return string_array; } -template -constexpr auto cat(std::arrayconst&... a) noexcept { +template +constexpr auto cat(std::array const&... a) noexcept { std::array out; std::size_t index{}; ((std::copy_n(a.begin(), Sizes, out.begin() + index), index += Sizes), ...); @@ -89,14 +89,14 @@ constexpr auto from_string_view(std::string_view sv) { } template - std::ostream &operator<<(std::ostream &os, tl::expected const &exp) { - if (exp.has_value()) { - os << "Value: '" << *exp << "'"; - } else { - os << "Error"; - } - return os; +std::ostream& operator<<(std::ostream& os, tl::expected const& exp) { + if (exp.has_value()) { + os << "Value: '" << *exp << "'"; + } else { + os << "Error"; } + return os; +} bool test_incomplete_message(auto const& payload) { // Test incomplete message. @@ -105,9 +105,9 @@ bool test_incomplete_message(auto const& payload) { msgpack::token_reader reader(std::span(payload.data(), i)); auto token = reader.read_one(); if (token != tl::make_unexpected(msgpack::error::incomplete_message)) { - fmt::print("Got the wrong response reading subview[0,{}] of payload: {}\n", - i, - token->get().value()); + fmt::print("Got the wrong response reading subview[0,{}] of " + "payload: {}\n", + i, token->get().value()); return false; } } @@ -115,11 +115,11 @@ bool test_incomplete_message(auto const& payload) { } bool test_end_of_message(auto& reader) { - return reader.read_one() == - tl::make_unexpected(msgpack::error::end_of_message); + return reader.read_one() + == tl::make_unexpected(msgpack::error::end_of_message); } -} +} // namespace suite reader_tests = [] { //-------------------------------------------------------------------------- @@ -173,8 +173,8 @@ suite reader_tests = [] { msgpack::token_reader reader(payload); auto token = reader.read_one(); expect(token && token->type() == msgpack::format::type::unsigned_int); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); expect(token->get() == 0x0102); expect(token->get() == 0x0102); expect(token->get() == 0x0102); @@ -193,10 +193,10 @@ suite reader_tests = [] { msgpack::token_reader reader(payload); auto token = reader.read_one(); expect(token && token->type() == msgpack::format::type::unsigned_int); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); expect(token->get() == 0x01020304); expect(token->get() == 0x01020304); expect(token == 0x01020304u); @@ -204,8 +204,8 @@ suite reader_tests = [] { expect(test_end_of_message(reader)); }; "read format::uint64"_test = [] { - constexpr auto payload = make_bytes(0xcf, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); + constexpr auto payload = make_bytes( + 0xcf, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); // Test incomplete message. expect(test_incomplete_message(payload)); @@ -214,12 +214,12 @@ suite reader_tests = [] { msgpack::token_reader reader(payload); auto token = reader.read_one(); expect(token && token->type() == msgpack::format::type::unsigned_int); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); expect(token->get() == 0x0102030405060708); expect(token == 0x0102030405060708u); // EOM @@ -277,8 +277,8 @@ suite reader_tests = [] { msgpack::token_reader reader(payload); auto token = reader.read_one(); expect(token && token->type() == msgpack::format::type::signed_int); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); expect(token->get() == -256); expect(token->get() == -256); expect(token->get() == -256); @@ -297,10 +297,10 @@ suite reader_tests = [] { msgpack::token_reader reader(payload); auto token = reader.read_one(); expect(token && token->type() == msgpack::format::type::signed_int); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); expect(token->get() == -65536); expect(token->get() == -65536); expect(token == -65536); @@ -308,8 +308,8 @@ suite reader_tests = [] { expect(test_end_of_message(reader)); }; "read format::int64"_test = [] { - constexpr auto payload = make_bytes(0xd3, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00); + constexpr auto payload = make_bytes( + 0xd3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00); // Test incomplete message. expect(test_incomplete_message(payload)); @@ -318,12 +318,12 @@ suite reader_tests = [] { msgpack::token_reader reader(payload); auto token = reader.read_one(); expect(token && token->type() == msgpack::format::type::signed_int); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); - expect(token->get() == - tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); + expect(token->get() + == tl::make_unexpected(msgpack::error::will_truncate)); expect(token->get() == -4294967296); expect(token == -4294967296); // EOM @@ -335,8 +335,7 @@ suite reader_tests = [] { //-------------------------------------------------------------------------- "read format::fixstr"_test = [] { constexpr std::string_view sv = "hello"; - constexpr auto payload = - cat(make_bytes(0xa5), + constexpr auto payload = cat(make_bytes(0xa5), generate_bytes([sv] { return from_string_view(sv); })); // Test incomplete message. @@ -355,8 +354,7 @@ suite reader_tests = [] { }; "read format::str8"_test = [] { constexpr std::string_view sv = "hello world"; - constexpr auto payload = - cat(make_bytes(0xd9, sv.size()), + constexpr auto payload = cat(make_bytes(0xd9, sv.size()), generate_bytes([sv] { return from_string_view(sv); })); // Test incomplete message. @@ -374,14 +372,12 @@ suite reader_tests = [] { expect(test_end_of_message(reader)); }; "read format::str16"_test = [] { - static constexpr auto sa = build_string([]{ - return repeat("0123456789abcdef", 17); - }); + static constexpr auto sa = + build_string([] { return repeat("0123456789abcdef", 17); }); constexpr auto sv = std::string_view(sa.data(), sa.size()); constexpr auto sv_size = host_to_be(std::uint16_t(sv.size())); - auto payload = - cat(make_bytes(0xda), as_bytes(sv_size), + auto payload = cat(make_bytes(0xda), as_bytes(sv_size), generate_bytes([] { return from_string_view(sv); })); // Test incomplete message. @@ -399,14 +395,12 @@ suite reader_tests = [] { expect(test_end_of_message(reader)); }; "read format::str32"_test = [] { - static constexpr auto sa = build_string([]{ - return repeat("0123456789abcdef", 4097); - }); + static constexpr auto sa = + build_string([] { return repeat("0123456789abcdef", 4097); }); constexpr auto sv = std::string_view(sa.data(), sa.size()); constexpr auto sv_size = host_to_be(std::uint32_t(sv.size())); - constexpr auto payload = - cat(make_bytes(0xdb), as_bytes(sv_size), + constexpr auto payload = cat(make_bytes(0xdb), as_bytes(sv_size), generate_bytes([sv] { return from_string_view(sv); })); // Test incomplete message. @@ -428,13 +422,11 @@ suite reader_tests = [] { // Binary format tests //-------------------------------------------------------------------------- "read format::bin8"_test = [] { - constexpr auto bytes = make_bytes( - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 - ); + constexpr auto bytes = make_bytes(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10); constexpr auto bytes_size = host_to_be(std::uint8_t(bytes.size())); constexpr auto payload = - cat(make_bytes(0xc4), as_bytes(bytes_size), bytes); + cat(make_bytes(0xc4), as_bytes(bytes_size), bytes); // Test incomplete message. expect(test_incomplete_message(payload)); @@ -452,7 +444,7 @@ suite reader_tests = [] { expect(test_end_of_message(reader)); }; "read format::bin16"_test = [] { - static constexpr auto bytes = generate_bytes([]{ + static constexpr auto bytes = generate_bytes([] { return repeat( make_bytes(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08), 16); @@ -477,7 +469,7 @@ suite reader_tests = [] { expect(test_end_of_message(reader)); }; "read format::bin32"_test = [] { - static constexpr auto bytes = generate_bytes([]{ + static constexpr auto bytes = generate_bytes([] { return repeat( make_bytes(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08), 8193); @@ -485,7 +477,7 @@ suite reader_tests = [] { constexpr auto bytes_size = host_to_be(std::uint32_t(bytes.size())); constexpr auto payload = - cat(make_bytes(0xc6), as_bytes(bytes_size), bytes); + cat(make_bytes(0xc6), as_bytes(bytes_size), bytes); // Test incomplete message. expect(test_incomplete_message(payload)); @@ -508,7 +500,7 @@ suite reader_tests = [] { "read format::fixarray"_test = [] { // A MessagePack array of 5 8-bit unsigned integers. constexpr auto payload = make_bytes(0x95, 0xcc, 0x85, 0xcc, 0x84, 0xcc, - 0x83, 0xcc, 0x82, 0xcc, 0x81); + 0x83, 0xcc, 0x82, 0xcc, 0x81); msgpack::token_reader reader(payload); auto token = reader.read_one(); @@ -517,16 +509,16 @@ suite reader_tests = [] { expect(array && array->count == 5); for (std::size_t i = 0; i < array->count; ++i) { - auto v = reader.read_one(); - expect(v && v->get() == 0x85 - i); + auto v = reader.read_one(); + expect(v && v->get() == 0x85 - i); } expect(test_end_of_message(reader)); }; "read format::array16"_test = [] { // A MessagePack array of 5 8-bit unsigned integers. - constexpr auto payload = make_bytes(0xdc, 0x00, 0x05, - 0xcc, 0x85, 0xcc, 0x84, 0xcc, 0x83, 0xcc, 0x82, 0xcc, 0x81); + constexpr auto payload = make_bytes(0xdc, 0x00, 0x05, 0xcc, 0x85, 0xcc, + 0x84, 0xcc, 0x83, 0xcc, 0x82, 0xcc, 0x81); msgpack::token_reader reader(payload); auto token = reader.read_one(); @@ -535,16 +527,16 @@ suite reader_tests = [] { expect(array && array->count == 5); for (std::size_t i = 0; i < array->count; ++i) { - auto v = reader.read_one(); - expect(v && v == 0x85u - i); + auto v = reader.read_one(); + expect(v && v == 0x85u - i); } expect(test_end_of_message(reader)); }; "read format::array32"_test = [] { // A MessagePack array of 5 8-bit unsigned integers. - constexpr auto payload = make_bytes(0xdd, 0x00, 0x00, 0x00, 0x05, - 0xcc, 0x85, 0xcc, 0x84, 0xcc, 0x83, 0xcc, 0x82, 0xcc, 0x81); + constexpr auto payload = make_bytes(0xdd, 0x00, 0x00, 0x00, 0x05, 0xcc, + 0x85, 0xcc, 0x84, 0xcc, 0x83, 0xcc, 0x82, 0xcc, 0x81); msgpack::token_reader reader(payload); auto token = reader.read_one(); @@ -553,8 +545,8 @@ suite reader_tests = [] { expect(array && array->count == 5); for (std::size_t i = 0; i < array->count; ++i) { - auto v = reader.read_one(); - expect(v && v->get() == 0x85 - i); + auto v = reader.read_one(); + expect(v && v->get() == 0x85 - i); } expect(test_end_of_message(reader)); @@ -562,18 +554,15 @@ suite reader_tests = [] { "read format::fixmap"_test = [] { // A MessagePack map of 3 strings to 8-bit unsigned integers. static constexpr std::array strings = { - "one", "two", "three" - }; + "one", "two", "three"}; - constexpr auto payload = cat( - make_bytes(0x83, 0xa3), + constexpr auto payload = cat(make_bytes(0x83, 0xa3), generate_bytes([] { return from_string_view(strings[0]); }), make_bytes(0x01, 0xa3), generate_bytes([] { return from_string_view(strings[1]); }), make_bytes(0x02, 0xa5), generate_bytes([] { return from_string_view(strings[2]); }), - make_bytes(0x03) - ); + make_bytes(0x03)); msgpack::token_reader reader(payload); auto token = reader.read_one(); @@ -593,18 +582,15 @@ suite reader_tests = [] { "read format::map16"_test = [] { // A MessagePack map of 3 strings to 8-bit unsigned integers. static constexpr std::array strings = { - "one", "two", "three" - }; + "one", "two", "three"}; - constexpr auto payload = cat( - make_bytes(0xde, 0x00, 0x03, 0xa3), + constexpr auto payload = cat(make_bytes(0xde, 0x00, 0x03, 0xa3), generate_bytes([] { return from_string_view(strings[0]); }), make_bytes(0x01, 0xa3), generate_bytes([] { return from_string_view(strings[1]); }), make_bytes(0x02, 0xa5), generate_bytes([] { return from_string_view(strings[2]); }), - make_bytes(0x03) - ); + make_bytes(0x03)); msgpack::token_reader reader(payload); auto token = reader.read_one(); @@ -626,8 +612,7 @@ suite reader_tests = [] { "read format::map32"_test = [] { // A MessagePack map of 3 strings to 8-bit unsigned integers. static constexpr std::array strings = { - "one", "two", "three" - }; + "one", "two", "three"}; constexpr auto payload = cat( make_bytes(0xdf, 0x00, 0x00, 0x00, 0x03, 0xa3), @@ -636,8 +621,7 @@ suite reader_tests = [] { generate_bytes([] { return from_string_view(strings[1]); }), make_bytes(0x02, 0xa5), generate_bytes([] { return from_string_view(strings[2]); }), - make_bytes(0x03) - ); + make_bytes(0x03)); msgpack::token_reader reader(payload); auto token = reader.read_one(); diff --git a/tests/msgpack/test_token_views.cpp b/tests/msgpack/test_token_views.cpp index 48daff8..88bf0d6 100644 --- a/tests/msgpack/test_token_views.cpp +++ b/tests/msgpack/test_token_views.cpp @@ -1,11 +1,12 @@ +#include +#include #include -#include #include #include -#include using namespace boost::ut; + namespace { template constexpr bool operator==(std::span a, std::span b) noexcept { @@ -18,17 +19,17 @@ constexpr std::array as_bytes(T&& t) { } template -constexpr std::array make_bytes(Bytes &&...bytes) { +constexpr std::array make_bytes(Bytes&&... bytes) { return {std::byte(std::forward(bytes))...}; } -template struct oversized_array { +template +struct oversized_array { std::array data; std::size_t size; }; - -constexpr auto to_bytes_array_oversized(auto const &container) { +constexpr auto to_bytes_array_oversized(auto const& container) { using value_type = std::decay_t; oversized_array arr; std::copy(std::begin(container), std::end(container), std::begin(arr.data)); @@ -51,8 +52,8 @@ consteval auto build_string(auto callable) { return string_array; } -template -constexpr auto cat(std::arrayconst&... a) noexcept { +template +constexpr auto cat(std::array const&... a) noexcept { std::array out; std::size_t index{}; ((std::copy_n(a.begin(), Sizes, out.begin() + index), index += Sizes), ...); @@ -89,14 +90,14 @@ constexpr auto from_string_view(std::string_view sv) { } template - std::ostream &operator<<(std::ostream &os, tl::expected const &exp) { - if (exp.has_value()) { - os << "Value: '" << *exp << "'"; - } else { - os << "Error"; - } - return os; +std::ostream& operator<<(std::ostream& os, tl::expected const& exp) { + if (exp.has_value()) { + os << "Value: '" << *exp << "'"; + } else { + os << "Error"; } + return os; +} bool test_incomplete_message(auto const& payload) { // Test incomplete message. @@ -105,9 +106,9 @@ bool test_incomplete_message(auto const& payload) { msgpack::token_reader reader(std::span(payload.data(), i)); auto token = reader.read_one(); if (token != tl::make_unexpected(msgpack::error::incomplete_message)) { - fmt::print("Got the wrong response reading subview[0,{}] of payload: {}\n", - i, - token->get().value()); + fmt::print("Got the wrong response reading subview[0,{}] of " + "payload: {}\n", + i, token->get().value()); return false; } } @@ -115,10 +116,10 @@ bool test_incomplete_message(auto const& payload) { } bool test_end_of_message(auto& reader) { - return reader.read_one() == - tl::make_unexpected(msgpack::error::end_of_message); -} + return reader.read_one() + == tl::make_unexpected(msgpack::error::end_of_message); } +} // namespace template <> struct fmt::formatter { @@ -126,9 +127,11 @@ struct fmt::formatter { constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } - template + + template auto format(msgpack::token const& v, FormatContext& ctx) const { - auto out = fmt::format_to(ctx.out(), "()))); @@ -143,8 +146,8 @@ struct fmt::formatter { out = fmt::format_to(out, "{}", (*(v.get()))); break; case msgpack::format::type::binary: - out = fmt::format_to(out, "{}", - (*(v.get>()))); + out = fmt::format_to( + out, "{}", (*(v.get>()))); break; case msgpack::format::type::map: out = fmt::format_to(out, "(arity: {})", @@ -160,8 +163,7 @@ struct fmt::formatter { case msgpack::format::type::invalid: out = fmt::format_to(out, "(invalid)"); break; - default: - break; + default: break; } return fmt::format_to(out, ">"); } @@ -171,11 +173,16 @@ suite views_tests = [] { "read format::fixmap"_test = [] { // A MessagePack map of 3 strings to 8-bit unsigned integers. static constexpr auto strings = std::to_array({ - "one", "two", "three", "array", "four", "map", "five", + "one", + "two", + "three", + "array", + "four", + "map", + "five", }); - constexpr auto payload = cat( - make_bytes(0x87, 0xa3), + constexpr auto payload = cat(make_bytes(0x87, 0xa3), generate_bytes([] { return from_string_view(strings[0]); }), make_bytes(0x01, 0xa3), @@ -201,7 +208,7 @@ suite views_tests = [] { make_bytes(0xa4), generate_bytes([] { return from_string_view(strings[6]); }) - //make_bytes(0x05) + // make_bytes(0x05) ); std::array tokens; diff --git a/tests/msgpack/test_utils.h b/tests/msgpack/test_utils.h index e05afe7..8b13270 100644 --- a/tests/msgpack/test_utils.h +++ b/tests/msgpack/test_utils.h @@ -2,9 +2,10 @@ #define msgpack_test_utils_4573e6627d8efe78 #include -#include #include +#include + template constexpr bool operator==(std::span a, std::span b) noexcept { return std::equal(a.begin(), a.end(), b.begin(), b.end()); @@ -16,16 +17,17 @@ constexpr std::array as_bytes(T&& t) { } template -constexpr std::array make_bytes(Bytes &&...bytes) { +constexpr std::array make_bytes(Bytes&&... bytes) { return {std::byte(std::forward(bytes))...}; } -template struct oversized_array { +template +struct oversized_array { std::array data; std::size_t size; }; -constexpr auto to_bytes_array_oversized(auto const &container) { +constexpr auto to_bytes_array_oversized(auto const& container) { using value_type = std::decay_t; oversized_array arr; std::copy(std::begin(container), std::end(container), std::begin(arr.data)); @@ -48,8 +50,8 @@ consteval auto build_string(auto callable) { return string_array; } -template -constexpr auto cat(std::arrayconst&... a) noexcept { +template +constexpr auto cat(std::array const&... a) noexcept { std::array out; std::size_t index{}; ((std::copy_n(a.begin(), Sizes, out.begin() + index), index += Sizes), ...); @@ -86,7 +88,7 @@ constexpr auto from_string_view(std::string_view sv) { } template -std::ostream &operator<<(std::ostream &os, tl::expected const &exp) { +std::ostream& operator<<(std::ostream& os, tl::expected const& exp) { if (exp.has_value()) { os << "Value: '" << *exp << "'"; } else { diff --git a/tests/msgpack/test_writer.cpp b/tests/msgpack/test_writer.cpp index b8815bb..c814be7 100644 --- a/tests/msgpack/test_writer.cpp +++ b/tests/msgpack/test_writer.cpp @@ -1,7 +1,5 @@ #include "parselink/msgpack/core/writer.h" - #include - #include using namespace boost::ut; @@ -10,76 +8,77 @@ namespace format = msgpack::format; namespace { template -constexpr std::array make_bytes(Bytes &&...bytes) { - return {std::byte(std::forward(bytes))...}; +constexpr std::array make_bytes(Bytes&&... bytes) { + return {std::byte(std::forward(bytes))...}; } -template struct oversized_array { - std::array data; - std::size_t size; +template +struct oversized_array { + std::array data; + std::size_t size; }; -constexpr auto to_bytes_array_oversized(auto const &container) { - oversized_array arr; - std::copy(std::begin(container), std::end(container), std::begin(arr.data)); - arr.size = std::distance(std::begin(container), std::end(container)); - return arr; +constexpr auto to_bytes_array_oversized(auto const& container) { + oversized_array arr; + std::copy(std::begin(container), std::end(container), std::begin(arr.data)); + arr.size = std::distance(std::begin(container), std::end(container)); + return arr; } consteval auto generate_bytes(auto callable) { - constexpr auto oversized = to_bytes_array_oversized(callable()); - std::array out; - std::copy(std::begin(oversized.data), + constexpr auto oversized = to_bytes_array_oversized(callable()); + std::array out; + std::copy(std::begin(oversized.data), std::next(std::begin(oversized.data), oversized.size), std::begin(out)); - return out; + return out; } template -consteval auto cat(std::array const &a, - std::array const &b) { - std::array out; - std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), +consteval auto cat( + std::array const& a, std::array const& b) { + std::array out; + std::copy(std::begin(a), std::next(std::begin(a), std::size(a)), std::begin(out)); - std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), + std::copy(std::begin(b), std::next(std::begin(b), std::size(b)), std::next(std::begin(out), std::size(a))); - return out; + return out; } template constexpr auto zip(T val, Itr begin, Itr end) { - std::vector output; - for (auto itr = begin; itr != end; ++itr) { - output.emplace_back(val); - output.emplace_back(*itr); - } - return output; + std::vector output; + for (auto itr = begin; itr != end; ++itr) { + output.emplace_back(val); + output.emplace_back(*itr); + } + return output; } template -constexpr auto zip(T val, Iterable const &itr) { - return zip(val, std::begin(itr), std::end(itr)); +constexpr auto zip(T val, Iterable const& itr) { + return zip(val, std::begin(itr), std::end(itr)); } constexpr auto from_string_view(std::string_view sv) { - std::vector range; - range.resize(sv.size()); - auto itr = range.begin(); - for (auto c : sv) { - *itr = std::byte(c); - ++itr; - } - return range; + std::vector range; + range.resize(sv.size()); + auto itr = range.begin(); + for (auto c : sv) { + *itr = std::byte(c); + ++itr; + } + return range; } constexpr auto make_contiguous_range(std::uint8_t start, std::uint8_t end) { - auto count = std::size_t(end) - std::size_t(start) + 1; - std::vector range; - range.resize(count); - for (auto i = std::size_t(start); i <= std::size_t(end); ++i) { - range[i - std::size_t(start)] = std::byte(i); - } - return range; + auto count = std::size_t(end) - std::size_t(start) + 1; + std::vector range; + range.resize(count); + for (auto i = std::size_t(start); i <= std::size_t(end); ++i) { + range[i - std::size_t(start)] = std::byte(i); + } + return range; } constexpr auto equal(auto a, auto b) { @@ -89,162 +88,175 @@ constexpr auto equal(auto a, auto b) { } // namespace suite writer = [] { - "writer empty span"_test = [] { - std::array payload; + "writer empty span"_test = [] { + std::array payload; - msgpack::writer writer(payload); - expect(writer.tell() == 0); - }; + msgpack::writer writer(payload); + expect(writer.tell() == 0); + }; - "writer::write"_test = [] { - using fmt = format::positive_fixint; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::positive_fixint; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0x32, 0x55); - msgpack::writer writer(payload); - auto result = writer.write(std::uint8_t{0x32}); - expect(!!result); - expect(writer.tell() == 1); - expect(*writer.subspan().begin() == std::byte{0x32}); - expect(writer.write(std::uint8_t{0x82}) == tl::make_unexpected(error::bad_value)); + std::array payload; + auto constexpr expected = make_bytes(0x32, 0x55); + msgpack::writer writer(payload); + auto result = writer.write(std::uint8_t{0x32}); + expect(!!result); + expect(writer.tell() == 1); + expect(*writer.subspan().begin() == std::byte{0x32}); + expect(writer.write(std::uint8_t{0x82}) + == tl::make_unexpected(error::bad_value)); - writer.write(std::uint8_t{0x55}); - expect(writer.tell() == 2); - expect(equal(writer.subspan(), expected)); - expect(writer.write(std::uint8_t{0x01}) == tl::make_unexpected(error::out_of_space)); - }; + writer.write(std::uint8_t{0x55}); + expect(writer.tell() == 2); + expect(equal(writer.subspan(), expected)); + expect(writer.write(std::uint8_t{0x01}) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::uint8; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::uint8; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xcc, 0x32, 0xcc, 0x82); - msgpack::writer writer(payload); - expect(!!writer.write(std::uint8_t{0x32})); - expect(writer.tell() == 2); - expect(equal(writer.subspan(), std::span{expected.begin(), 2})); - expect(!!writer.write(std::uint8_t{0x82})); - expect(equal(writer.subspan(), expected)); - expect(writer.write(std::uint8_t{0x01}) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes(0xcc, 0x32, 0xcc, 0x82); + msgpack::writer writer(payload); + expect(!!writer.write(std::uint8_t{0x32})); + expect(writer.tell() == 2); + expect(equal(writer.subspan(), std::span{expected.begin(), 2})); + expect(!!writer.write(std::uint8_t{0x82})); + expect(equal(writer.subspan(), expected)); + expect(writer.write(std::uint8_t{0x01}) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::uint16; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::uint16; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xcd, 0x32, 0xcc, 0xcd, 0xaa, 0xff); - msgpack::writer writer(payload); - expect(!!writer.write(std::uint16_t{0x32cc})); - expect(writer.tell() == 3); - expect(equal(writer.subspan(), std::span{expected.begin(), 3})); - expect(!!writer.write(0xaaff)); - expect(equal(writer.subspan(), expected)); - expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = + make_bytes(0xcd, 0x32, 0xcc, 0xcd, 0xaa, 0xff); + msgpack::writer writer(payload); + expect(!!writer.write(std::uint16_t{0x32cc})); + expect(writer.tell() == 3); + expect(equal(writer.subspan(), std::span{expected.begin(), 3})); + expect(!!writer.write(0xaaff)); + expect(equal(writer.subspan(), expected)); + expect(writer.write(0x01) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::uint32; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::uint32; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xce, 0x01, 0x02, 0x03, 0x04); - msgpack::writer writer(payload); - expect(!!writer.write(0x01020304)); - expect(writer.tell() == 5); - expect(equal(writer.subspan(), expected)); - expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes(0xce, 0x01, 0x02, 0x03, 0x04); + msgpack::writer writer(payload); + expect(!!writer.write(0x01020304)); + expect(writer.tell() == 5); + expect(equal(writer.subspan(), expected)); + expect(writer.write(0x01) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::uint64; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::uint64; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes( - 0xcf, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); - msgpack::writer writer(payload); - expect(!!writer.write(0x0102030405060708)); - expect(writer.tell() == 9); - expect(equal(writer.subspan(), expected)); - expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes( + 0xcf, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); + msgpack::writer writer(payload); + expect(!!writer.write(0x0102030405060708)); + expect(writer.tell() == 9); + expect(equal(writer.subspan(), expected)); + expect(writer.write(0x01) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::negative_fixint; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::negative_fixint; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xff, 0xe0); - msgpack::writer writer(payload); - expect(!!writer.write(-1)); - expect(writer.tell() == 1); - expect(*writer.subspan().begin() == std::byte{0xff}); - expect(writer.write(-33) == tl::make_unexpected(error::bad_value)); - expect(!!writer.write(-32)); - expect(writer.tell() == 2); - expect(equal(writer.subspan(), expected)); - expect(writer.write(-5) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes(0xff, 0xe0); + msgpack::writer writer(payload); + expect(!!writer.write(-1)); + expect(writer.tell() == 1); + expect(*writer.subspan().begin() == std::byte{0xff}); + expect(writer.write(-33) == tl::make_unexpected(error::bad_value)); + expect(!!writer.write(-32)); + expect(writer.tell() == 2); + expect(equal(writer.subspan(), expected)); + expect(writer.write(-5) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::int8; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::int8; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xd0, 0x32, 0xd0, 0xfb); - msgpack::writer writer(payload); - expect(!!writer.write(std::int8_t{0x32})); - expect(writer.tell() == 2); - expect(equal(writer.subspan(), std::span{expected.begin(), 2})); - expect(!!writer.write(std::int8_t{-5})); - expect(equal(writer.subspan(), expected)); - expect(writer.write(std::uint8_t{0x01}) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes(0xd0, 0x32, 0xd0, 0xfb); + msgpack::writer writer(payload); + expect(!!writer.write(std::int8_t{0x32})); + expect(writer.tell() == 2); + expect(equal(writer.subspan(), std::span{expected.begin(), 2})); + expect(!!writer.write(std::int8_t{-5})); + expect(equal(writer.subspan(), expected)); + expect(writer.write(std::uint8_t{0x01}) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::int16; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::int16; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xd1, 0x32, 0xcc, 0xd1, 0xff, 0xfa); - msgpack::writer writer(payload); - expect(!!writer.write(std::int16_t{0x32cc})); - expect(writer.tell() == 3); - expect(equal(writer.subspan(), std::span{expected.begin(), 3})); - expect(!!writer.write(-6)); - expect(equal(writer.subspan(), expected)); - expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = + make_bytes(0xd1, 0x32, 0xcc, 0xd1, 0xff, 0xfa); + msgpack::writer writer(payload); + expect(!!writer.write(std::int16_t{0x32cc})); + expect(writer.tell() == 3); + expect(equal(writer.subspan(), std::span{expected.begin(), 3})); + expect(!!writer.write(-6)); + expect(equal(writer.subspan(), expected)); + expect(writer.write(0x01) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::int32; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::int32; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes(0xd2, 0x01, 0x02, 0x03, 0x04); - msgpack::writer writer(payload); - expect(!!writer.write(0x01020304)); - expect(writer.tell() == 5); - expect(equal(writer.subspan(), expected)); - expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes(0xd2, 0x01, 0x02, 0x03, 0x04); + msgpack::writer writer(payload); + expect(!!writer.write(0x01020304)); + expect(writer.tell() == 5); + expect(equal(writer.subspan(), expected)); + expect(writer.write(0x01) + == tl::make_unexpected(error::out_of_space)); + }; - "writer::write"_test = [] { - using fmt = format::int64; - using error = msgpack::error; + "writer::write"_test = [] { + using fmt = format::int64; + using error = msgpack::error; - std::array payload; - auto constexpr expected = make_bytes( - 0xd3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); - msgpack::writer writer(payload); - expect(!!writer.write(std::int64_t{0x0102030405060708})); - expect(writer.tell() == 9); - expect(equal(writer.subspan(), expected)); - expect(writer.write(0x01) == tl::make_unexpected(error::out_of_space)); - }; + std::array payload; + auto constexpr expected = make_bytes( + 0xd3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08); + msgpack::writer writer(payload); + expect(!!writer.write(std::int64_t{0x0102030405060708})); + expect(writer.tell() == 9); + expect(equal(writer.subspan(), expected)); + expect(writer.write(0x01) + == tl::make_unexpected(error::out_of_space)); + }; "writer::write"_test = [] { using fmt = format::fixstr; @@ -259,15 +271,14 @@ suite writer = [] { "writer::write"_test = [] { using fmt = format::str8; std::array payload; - auto constexpr expected = make_bytes(0xd9, 44, - 't', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', - 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', - 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', ' ', - 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g'); + auto constexpr expected = make_bytes(0xd9, 44, 't', 'h', 'e', ' ', 'q', + 'u', 'i', 'c', 'k', ' ', 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', + 'x', ' ', 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', + ' ', 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', + 'g'); msgpack::writer writer(payload); - std::string_view txt = - "the quick brown fox jumped over the lazy dog"; + std::string_view txt = "the quick brown fox jumped over the lazy dog"; expect(!!writer.write(std::move(txt))); expect(equal(writer.subspan(), expected)); }; @@ -275,15 +286,14 @@ suite writer = [] { "writer::write"_test = [] { using fmt = format::str16; std::array payload; - auto constexpr expected = make_bytes(0xda, 0, 44, - 't', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', - 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', - 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', ' ', - 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g'); + auto constexpr expected = make_bytes(0xda, 0, 44, 't', 'h', 'e', ' ', + 'q', 'u', 'i', 'c', 'k', ' ', 'b', 'r', 'o', 'w', 'n', ' ', 'f', + 'o', 'x', ' ', 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', + 'r', ' ', 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', + 'g'); msgpack::writer writer(payload); - std::string_view txt = - "the quick brown fox jumped over the lazy dog"; + std::string_view txt = "the quick brown fox jumped over the lazy dog"; expect(!!writer.write(std::move(txt))); expect(equal(writer.subspan(), expected)); }; @@ -291,15 +301,14 @@ suite writer = [] { "writer::write"_test = [] { using fmt = format::str32; std::array payload; - auto constexpr expected = make_bytes(0xdb, 0, 0, 0, 44, - 't', 'h', 'e', ' ', 'q', 'u', 'i', 'c', 'k', ' ', - 'b', 'r', 'o', 'w', 'n', ' ', 'f', 'o', 'x', ' ', - 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', 'e', 'r', ' ', - 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', 'o', 'g'); + auto constexpr expected = make_bytes(0xdb, 0, 0, 0, 44, 't', 'h', 'e', + ' ', 'q', 'u', 'i', 'c', 'k', ' ', 'b', 'r', 'o', 'w', 'n', ' ', + 'f', 'o', 'x', ' ', 'j', 'u', 'm', 'p', 'e', 'd', ' ', 'o', 'v', + 'e', 'r', ' ', 't', 'h', 'e', ' ', 'l', 'a', 'z', 'y', ' ', 'd', + 'o', 'g'); msgpack::writer writer(payload); - std::string_view txt = - "the quick brown fox jumped over the lazy dog"; + std::string_view txt = "the quick brown fox jumped over the lazy dog"; expect(!!writer.write(std::move(txt))); expect(equal(writer.subspan(), expected)); }; @@ -307,8 +316,8 @@ suite writer = [] { "writer::write"_test = [] { using fmt = format::bin8; std::array payload; - auto constexpr expected = make_bytes(0xc4, 0x07, 0x01, 0x02, 0x03, 0x04, - 0xf8, 0xf9, 0xfa); + auto constexpr expected = make_bytes( + 0xc4, 0x07, 0x01, 0x02, 0x03, 0x04, 0xf8, 0xf9, 0xfa); msgpack::writer writer(payload); std::span bv(expected.begin() + 2, expected.end()); @@ -319,8 +328,8 @@ suite writer = [] { "writer::write"_test = [] { using fmt = format::bin16; std::array payload; - auto constexpr expected = make_bytes(0xc5, 0x0, 0x07, 0x01, 0x02, 0x03, - 0x04, 0xf8, 0xf9, 0xfa); + auto constexpr expected = make_bytes( + 0xc5, 0x0, 0x07, 0x01, 0x02, 0x03, 0x04, 0xf8, 0xf9, 0xfa); msgpack::writer writer(payload); std::span bv(expected.begin() + 3, expected.end());