diff --git a/include/parselink/msgpack/core/packer.h b/include/parselink/msgpack/core/packer.h index 807de66..6998ee6 100644 --- a/include/parselink/msgpack/core/packer.h +++ b/include/parselink/msgpack/core/packer.h @@ -66,17 +66,37 @@ public: , 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&& v) noexcept { + using diff_type = + std::iterator_traits::difference_type; + 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 { - using diff_type = - std::iterator_traits::difference_type; - diff_type const space_needed = builtin_packer::total_size(v); - if (space_needed > std::distance(curr_, end_)) { - return tl::make_unexpected(error::out_of_space); - } else { - curr_ = builtin_packer::pack(v, curr_); - return tl::monostate{}; - } + context ctx{curr_, end_}; + // If packing is successful, it updates iterators. + return ctx.pack(std::forward(v)).map([&]{ + curr_ = ctx.out; + end_ = ctx.end; + }); } constexpr auto tell() const noexcept {