Additional concepts work
This commit is contained in:
parent
b48eddb8d0
commit
0cafb9bcd7
@ -18,6 +18,7 @@
|
|||||||
#ifndef msgpack_core_detail_builtin_packable_types_41bd88d512497527
|
#ifndef msgpack_core_detail_builtin_packable_types_41bd88d512497527
|
||||||
#define msgpack_core_detail_builtin_packable_types_41bd88d512497527
|
#define msgpack_core_detail_builtin_packable_types_41bd88d512497527
|
||||||
|
|
||||||
|
#include "parselink/msgpack/core/detail/packable_concepts.h"
|
||||||
#include "parselink/msgpack/core/format.h"
|
#include "parselink/msgpack/core/format.h"
|
||||||
#include "parselink/msgpack/util/endianness.h"
|
#include "parselink/msgpack/util/endianness.h"
|
||||||
|
|
||||||
@ -284,17 +285,6 @@ struct builtin_packer<map_desc> : builtin_packer_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Requirements for builtin_packable types.
|
|
||||||
template <typename T, typename Packer = detail::dummy_packer>
|
|
||||||
concept builtin_packable = requires(T&& value, Packer& dest) {
|
|
||||||
{
|
|
||||||
builtin_packer<std::remove_cvref_t<T>>::total_size(value)
|
|
||||||
} -> std::same_as<std::size_t>;
|
|
||||||
{
|
|
||||||
builtin_packer<std::remove_cvref_t<T>>::pack(value, dest)
|
|
||||||
} -> std::same_as<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace msgpack
|
} // namespace msgpack
|
||||||
|
|
||||||
#endif // msgpack_core_detail_builtin_packable_types_41bd88d512497527
|
#endif // msgpack_core_detail_builtin_packable_types_41bd88d512497527
|
||||||
|
|||||||
86
include/parselink/msgpack/core/detail/packable_concepts.h
Normal file
86
include/parselink/msgpack/core/detail/packable_concepts.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// ___ __ _ _
|
||||||
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
||||||
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
||||||
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
||||||
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Author: Kurt Sassenrath
|
||||||
|
// Module: msgpack
|
||||||
|
//
|
||||||
|
// Concepts used for types that are packable by a packer.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2023 Kurt Sassenrath.
|
||||||
|
//
|
||||||
|
// License TBD.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#ifndef msgpack_core_detail_packable_concepts_397b5e0ae6de61bf
|
||||||
|
#define msgpack_core_detail_packable_concepts_397b5e0ae6de61bf
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
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 packer_context_model {
|
||||||
|
std::byte* out;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// Packers with built-in support will specialize builtin_packer.
|
||||||
|
template <typename>
|
||||||
|
struct builtin_packer;
|
||||||
|
|
||||||
|
// Packers
|
||||||
|
template <typename>
|
||||||
|
struct packer_adapter;
|
||||||
|
|
||||||
|
template <typename T, template <typename> typename Packer,
|
||||||
|
typename Context = detail::packer_context_model>
|
||||||
|
concept packable_with = requires(T&& value, Context& dest) {
|
||||||
|
{
|
||||||
|
Packer<std::remove_cvref_t<T>>::total_size(value)
|
||||||
|
} -> std::same_as<std::size_t>;
|
||||||
|
{
|
||||||
|
Packer<std::remove_cvref_t<T>>::pack(value, dest)
|
||||||
|
} -> std::same_as<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept custom_packable = packable_with<T, packer_adapter>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept builtin_packable = packable_with<T, builtin_packer>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept packable = builtin_packable<T> || custom_packable<T>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
struct packer_impl_s;
|
||||||
|
|
||||||
|
template <custom_packable T>
|
||||||
|
struct packer_impl_s<T> {
|
||||||
|
using type = packer_adapter<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <builtin_packable T>
|
||||||
|
struct packer_impl_s<T> {
|
||||||
|
using type = builtin_packer<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using packer_impl = packer_impl_s<T>::type;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace msgpack
|
||||||
|
|
||||||
|
#endif // msgpack_core_detail_packable_concepts_397b5e0ae6de61bf
|
||||||
@ -21,7 +21,8 @@
|
|||||||
#ifndef msgpack_core_detail_packable_ranges_10d28c24498828c7
|
#ifndef msgpack_core_detail_packable_ranges_10d28c24498828c7
|
||||||
#define msgpack_core_detail_packable_ranges_10d28c24498828c7
|
#define msgpack_core_detail_packable_ranges_10d28c24498828c7
|
||||||
|
|
||||||
#include "builtin_packable_types.h"
|
#include "parselink/msgpack/core/detail/packable_concepts.h"
|
||||||
|
#include "parselink/msgpack/core/detail/builtin_packable_types.h"
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
@ -31,10 +32,7 @@ namespace detail {
|
|||||||
//
|
//
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept packable_array = std::ranges::input_range<T>
|
concept packable_array = std::ranges::input_range<T>
|
||||||
&& builtin_packable<std::ranges::range_value_t<T>>;
|
&& packable<std::ranges::range_value_t<T>>;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept tuple_like = requires(T t) { typename std::tuple_size<T>::type; };
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept key_value_pairlike = requires(T t) {
|
concept key_value_pairlike = requires(T t) {
|
||||||
|
|||||||
@ -38,8 +38,10 @@
|
|||||||
#ifndef msgpack_core_packer_1d5939e9c1498568
|
#ifndef msgpack_core_packer_1d5939e9c1498568
|
||||||
#define msgpack_core_packer_1d5939e9c1498568
|
#define msgpack_core_packer_1d5939e9c1498568
|
||||||
|
|
||||||
|
#include "parselink/msgpack/core/detail/packable_concepts.h"
|
||||||
#include "parselink/msgpack/core/detail/builtin_packable_types.h"
|
#include "parselink/msgpack/core/detail/builtin_packable_types.h"
|
||||||
#include "parselink/msgpack/core/detail/packable_ranges.h"
|
#include "parselink/msgpack/core/detail/packable_ranges.h"
|
||||||
|
|
||||||
#include "parselink/msgpack/core/error.h"
|
#include "parselink/msgpack/core/error.h"
|
||||||
#include "parselink/msgpack/core/format.h"
|
#include "parselink/msgpack/core/format.h"
|
||||||
#include "parselink/msgpack/util/endianness.h"
|
#include "parselink/msgpack/util/endianness.h"
|
||||||
@ -54,9 +56,6 @@ namespace msgpack {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct pack_adapter {};
|
struct pack_adapter {};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept packable_type = builtin_packable<T>;
|
|
||||||
|
|
||||||
class packer {
|
class packer {
|
||||||
// Replace with output_range?
|
// Replace with output_range?
|
||||||
using BufferType = std::span<std::byte>;
|
using BufferType = std::span<std::byte>;
|
||||||
@ -75,20 +74,21 @@ public:
|
|||||||
return std::ranges::distance(out, end);
|
return std::ranges::distance(out, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <packable_type T>
|
template <packable T>
|
||||||
constexpr tl::expected<tl::monostate, error> pack(T const& v) noexcept {
|
constexpr tl::expected<tl::monostate, error> pack(T const& v) noexcept {
|
||||||
auto rem = remaining();
|
auto rem = remaining();
|
||||||
decltype(rem) needed = builtin_packer<T>::total_size(v);
|
using packer_impl = detail::packer_impl<T>;
|
||||||
|
decltype(rem) needed = packer_impl::total_size(v);
|
||||||
if (needed > rem) {
|
if (needed > rem) {
|
||||||
return tl::make_unexpected(error::out_of_space);
|
return tl::make_unexpected(error::out_of_space);
|
||||||
} else {
|
} else {
|
||||||
builtin_packer<T>::pack(v, *this);
|
packer_impl::pack(v, *this);
|
||||||
return tl::monostate{};
|
return tl::monostate{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <packable_type T>
|
template <packable T>
|
||||||
constexpr tl::expected<tl::monostate, error> pack(T&& v) noexcept {
|
constexpr tl::expected<tl::monostate, error> pack(T&& v) noexcept {
|
||||||
context ctx{curr_, end_};
|
context ctx{curr_, end_};
|
||||||
// If packing is successful, it updates iterators.
|
// If packing is successful, it updates iterators.
|
||||||
|
|||||||
@ -292,7 +292,7 @@ bool test_deduced() noexcept {
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
suite packer = [] {
|
suite packer_single_format = [] {
|
||||||
"packer::pack<bool>"_test = [] { expect(test_deduced<bool>()); };
|
"packer::pack<bool>"_test = [] { expect(test_deduced<bool>()); };
|
||||||
"packer::pack<nil>"_test = [] { expect(test_deduced<msgpack::nil>()); };
|
"packer::pack<nil>"_test = [] { expect(test_deduced<msgpack::nil>()); };
|
||||||
"packer::pack<invalid>"_test = [] {
|
"packer::pack<invalid>"_test = [] {
|
||||||
@ -387,3 +387,26 @@ suite packer = [] {
|
|||||||
expect(test_deduced<msgpack::map_desc>());
|
expect(test_deduced<msgpack::map_desc>());
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
suite packer_ranges = [] {
|
||||||
|
"packer::pack<std::array/std::span<int>>"_test = [] {
|
||||||
|
constexpr auto data_array = std::to_array<int>({5, 10, 15, 20});
|
||||||
|
constexpr auto expected =
|
||||||
|
make_bytes(0x94, 0xd0, 0x05, 0xd0, 0xa, 0xd0, 0xf, 0xd0, 0x14);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::array<std::byte, std::size(expected)> payload;
|
||||||
|
msgpack::packer packer(payload);
|
||||||
|
expect(!!packer.pack(data_array));
|
||||||
|
expect(std::ranges::equal(payload, expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::span data_span{data_array};
|
||||||
|
std::array<std::byte, std::size(expected)> payload;
|
||||||
|
msgpack::packer packer(payload);
|
||||||
|
expect(!!packer.pack(data_span));
|
||||||
|
expect(std::ranges::equal(payload, expected));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user