diff --git a/include/parselink/msgpack/core/detail/builtin_unpackable_types.h b/include/parselink/msgpack/core/detail/builtin_unpackable_types.h new file mode 100644 index 0000000..932a7e1 --- /dev/null +++ b/include/parselink/msgpack/core/detail/builtin_unpackable_types.h @@ -0,0 +1,122 @@ +//----------------------------------------------------------------------------- +// ___ __ _ _ +// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ +// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / +// / ___/ (_| | | \__ \ __/ /__| | | | | < +// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . +// +//----------------------------------------------------------------------------- +// Author: Kurt Sassenrath +// Module: msgpack +// +// Support for unpacking various types. +// +// Copyright (c) 2023 Kurt Sassenrath. +// +// License TBD. +//----------------------------------------------------------------------------- +#ifndef msgpack_core_detail_builtin_unpackable_types_bf5de632f088a7d8 +#define msgpack_core_detail_builtin_unpackable_types_bf5de632f088a7d8 + +#include "parselink/msgpack/core/detail/unpackable_concepts.h" +#include "parselink/msgpack/core/error.h" +#include "parselink/msgpack/core/format.h" +#include "parselink/msgpack/util/endianness.h" + +#include + +#include +#include +#include + +namespace msgpack { +namespace detail { + +// This is a generic helper function for writing integral bytes +template +constexpr decltype(auto) unpack_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))); + } +} + +// Defines a range of bytes for binary formats. +template +concept byte_range = std::ranges::contiguous_range + && std::same_as, std::byte>; + +} // namespace detail + +template +struct builtin_unpacker; + +//////////////////////////////////////////////////////////////////////////////// +// Built-in unpacker specializations +//////////////////////////////////////////////////////////////////////////////// +template <> +struct builtin_unpacker { + static constexpr bool accept(std::byte marker) noexcept { + return marker == format::nil::marker; + } + + static constexpr auto unpack(auto& unpacker) noexcept { + ++unpacker.in; + return invalid{}; + } +}; + +template <> +struct builtin_unpacker { + static constexpr bool accept(std::byte marker) noexcept { + return marker == format::nil::marker; + } + + static constexpr auto unpack(auto& unpacker) noexcept { + ++unpacker.in; + return nil{}; + } +}; + +template <> +struct builtin_unpacker { + static constexpr bool accept(std::byte marker) noexcept { + return (marker & ~format::boolean::mask) == format::boolean::marker; + } + + static constexpr auto unpack(auto& unpacker) noexcept { + // In this case, we will not run out of room + return static_cast((*(unpacker.in)++) & ~format::boolean::mask); + } +}; + +// This unpacker will accept any uintX, positive_fixint types. +struct unsigned_int_unpacker { + static constexpr bool accept(std::byte marker) noexcept { + if (!(marker & 0x80)) { + return true; + } + switch (marker) { + case format::uint8::marker: + case format::uint16::marker: + case format::uint32::marker: + case format::uint64::marker: + return true; + default: + break; + } + return false; + } +}; + +template +struct builtin_unpacker { + static constexpr bool accept(std::byte marker) noexcept { + } +} + +} // namespace msgpack + +#endif // msgpack_core_detail_builtin_unpackable_types_bf5de632f088a7d8 diff --git a/include/parselink/msgpack/core/detail/packable_concepts.h b/include/parselink/msgpack/core/detail/packable_concepts.h index 2c769f1..c95d6bd 100644 --- a/include/parselink/msgpack/core/detail/packable_concepts.h +++ b/include/parselink/msgpack/core/detail/packable_concepts.h @@ -1,4 +1,3 @@ - //----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ diff --git a/include/parselink/msgpack/core/detail/unpackable_concepts.h b/include/parselink/msgpack/core/detail/unpackable_concepts.h new file mode 100644 index 0000000..835f620 --- /dev/null +++ b/include/parselink/msgpack/core/detail/unpackable_concepts.h @@ -0,0 +1,86 @@ +//----------------------------------------------------------------------------- +// ___ __ _ _ +// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ +// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / +// / ___/ (_| | | \__ \ __/ /__| | | | | < +// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . +// +//----------------------------------------------------------------------------- +// Author: Kurt Sassenrath +// Module: msgpack +// +// Concepts used for types that are deserializable by an unpacker. +// +// Copyright (c) 2023 Kurt Sassenrath. +// +// License TBD. +//----------------------------------------------------------------------------- +#ifndef msgpack_core_detail_unpackable_concepts_cf142e37b34a598f +#define msgpack_core_detail_unpackable_concepts_cf142e37b34a598f + +#include +#include +#include + +namespace msgpack { +namespace detail { + +// This structure models a minimal packer context. It is used to validate +// whether a particular type is considered packable or not. +struct unpacker_context_model { + std::byte* in; +}; + +} // namespace detail + +// Datatypes with built-in support will specialize builtin_unpacker. +template +struct builtin_unpacker; + +// Datatypes can have a custom adapter for unpacking. This _can_ be used to +// override default behavior if necessary, but its intended for custom types. +template +struct unpacker_adapter; + +template typename Unpacker, + typename Context = detail::unpacker_context_model> +concept unpackable_with = requires(T&& value, Context& dest) { + //{ + //Unpacker>::total_size(value) + //} -> std::same_as; + { + Unpacker>::unpack(dest) + } -> std::same_as; +}; + +template +concept custom_unpackable = unpackable_with; + +template +concept builtin_unpackable = unpackable_with; + +template +concept supports_unpack = builtin_unpackable || custom_unpackable; + +namespace detail { + + template + struct unpacker_impl_s; + + template + struct unpacker_impl_s { + using type = unpacker_adapter; + }; + + template + struct unpacker_impl_s { + using type = builtin_unpacker; + }; + + template + using unpacker_impl = unpacker_impl_s::type; +} // namespace detail + +} // namespace msgpack + +#endif // msgpack_core_detail_unpackable_concepts_cf142e37b34a598f diff --git a/include/parselink/msgpack/core/packer.h b/include/parselink/msgpack/core/packer.h index c14064b..cd59b99 100644 --- a/include/parselink/msgpack/core/packer.h +++ b/include/parselink/msgpack/core/packer.h @@ -53,9 +53,6 @@ namespace msgpack { -template -struct pack_adapter {}; - class packer { // Replace with output_range? using BufferType = std::span; @@ -93,9 +90,8 @@ public: context ctx{curr_, end_}; // If packing is successful, it updates iterators. auto ret = ctx.pack(std::forward(v)); - if (!!ret) { + if (ret) { curr_ = ctx.out; - end_ = ctx.end; } return ret; } diff --git a/include/parselink/msgpack/core/unpacker.h b/include/parselink/msgpack/core/unpacker.h new file mode 100644 index 0000000..d118ed0 --- /dev/null +++ b/include/parselink/msgpack/core/unpacker.h @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------------- +// ___ __ _ _ +// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ +// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / +// / ___/ (_| | | \__ \ __/ /__| | | | | < +// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . +// +//----------------------------------------------------------------------------- +// Author: Kurt Sassenrath +// Module: msgpack +// +// Default unpacker implementation, utilizing pull-style parsing semantics for +// deserializing data with an expected structure akin to a schema. +// +// The default unpacker maintains some flexibility in how data was originally +// packed. +// +// E.g. If a std::uint8_t is requested, it is perfectly valid to read a uint32 +// format, provided the stored value is less than 255. +// +// core/reader (to be renamed verbatim_unpacker) can be utilized in scenarios +// where code size is critical and exact type matching is not a considerable +// downside. +// +// For schemaless data, the token API can be used instead. +// +// Copyright (c) 2023 Kurt Sassenrath. +// +// License TBD. +//----------------------------------------------------------------------------- +#ifndef msgpack_core_unpacker_910ec357d397ac7e +#define msgpack_core_unpacker_910ec357d397ac7e + +#include "parselink/msgpack/core/detail/builtin_unpackable_types.h" +#include "parselink/msgpack/core/detail/unpackable_concepts.h" +#include "parselink/msgpack/core/error.h" + +#include + +#include +#include + +namespace msgpack { + +class unpacker { + using BufferType = std::span; + +public: + constexpr unpacker(BufferType buff) + : buff_(buff) + , curr_(std::begin(buff_)) + , end_(std::end(buff_)) {} + + // IDK if we need this yet + struct context { + decltype(std::begin(BufferType{})) in; + decltype(std::begin(BufferType{})) end; + + constexpr auto remaining() noexcept { + return std::ranges::distance(in, end); + } + + template + constexpr tl::expected unpack() noexcept { + if (remaining() == 0) + return tl::make_unexpected(error::end_of_message); + using unpacker_impl = detail::unpacker_impl; + return unpacker_impl::unpack(*this); + } + }; + + template + constexpr tl::expected unpack() noexcept { + context ctx{curr_, end_}; + auto ret = ctx.unpack(); + if (ret) { + curr_ = ctx.in; + } + return ret; + } + +private: + BufferType buff_; + decltype(std::begin(buff_)) curr_; + decltype(std::end(buff_)) end_; +}; + +} // namespace msgpack + +#endif // msgpack_core_unpacker_910ec357d397ac7e