//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // //----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: msgpack // // Default packer implementation, which aims to deduce the best format to use // for a given value. For example, if a 32-bit unsigned integer type only // contains the value 5, a uint32 format would serialize into: // // 0xce, 0x00, 0x00, 0x00, 0x05 // // Instead, the packer will note that this value could be stored in a positive // fixint, which is simply: // // 0x05 // // The same optimization will be applied to variable-length types, like strings, // bytes, arrays, and maps. // // This flexibility comes at the cost of CPU instructions. For embedded targets, // writer (to be renamed verbatim_packer in the future) may be a better choice. // // Future goals for this particular packer: // 1. Support containers/ranges seamlessly. // 2. Support packing of trivial POD structures without an explicit // pack_adapter. // // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. //----------------------------------------------------------------------------- #ifndef msgpack_core_packer_1d5939e9c1498568 #define msgpack_core_packer_1d5939e9c1498568 #include "parselink/msgpack/core/detail/builtin_packable_types.h" #include "parselink/msgpack/core/detail/packable_ranges.h" #include "parselink/msgpack/core/error.h" #include "parselink/msgpack/core/format.h" #include "parselink/msgpack/util/endianness.h" #include #include #include namespace msgpack { template struct pack_adapter {}; template concept packable_type = builtin_packable; class packer { // Replace with output_range? using BufferType = std::span; public: constexpr packer(BufferType buff) : buff_(buff) , curr_(std::begin(buff_)) , end_(std::end(buff_)) {} struct context { decltype(std::begin(BufferType{})) out; decltype(std::begin(BufferType{})) end; constexpr auto remaining() noexcept { return std::ranges::distance(out, end); } template constexpr tl::expected pack(T const& v) noexcept { auto rem = remaining(); decltype(rem) needed = builtin_packer::total_size(v); if (needed > rem) { return tl::make_unexpected(error::out_of_space); } else { builtin_packer::pack(v, *this); return tl::monostate{}; } } }; template constexpr tl::expected pack(T&& v) noexcept { context ctx{curr_, end_}; // If packing is successful, it updates iterators. auto ret = ctx.pack(std::forward(v)); if (!!ret) { curr_ = ctx.out; end_ = ctx.end; } return ret; } constexpr auto tell() const noexcept { return std::distance(std::begin(buff_), curr_); } constexpr auto subspan() const noexcept { return buff_.subspan(0, tell()); } private: BufferType buff_; decltype(std::begin(buff_)) curr_; decltype(std::end(buff_)) end_; }; } // namespace msgpack #endif // msgpack_core_packer_1d5939e9c1498568