userver: userver/dump/aggregates.hpp Source File
Loading...
Searching...
No Matches
aggregates.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/dump/aggregates.hpp
4/// @brief Dumping support for aggregates
5///
6/// @ingroup userver_dump_read_write
7
8#include <type_traits>
9
10#include <boost/pfr/core.hpp>
11#include <boost/pfr/tuple_size.hpp>
12
13#include <userver/dump/operations.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace dump {
18
19template <typename T>
21
22namespace impl {
23
24// Only the non-specialized IsDumpedAggregate struct is defined,
25// the specializations are declared without a definition
26template <typename T>
27using IsNotDumpedAggregate = decltype(sizeof(IsDumpedAggregate<T>));
28
29template <typename T, std::size_t... Indices>
30constexpr bool AreAllDumpable(std::index_sequence<Indices...>) {
31 return (kIsDumpable<boost::pfr::tuple_element_t<Indices, T>> && ...);
32}
33
34template <typename T>
35constexpr bool IsDumpableAggregate() {
36 if constexpr (std::is_aggregate_v<T> && !meta::kIsDetected<IsNotDumpedAggregate, T>) {
37 constexpr auto kSize = boost::pfr::tuple_size_v<T>;
38 static_assert(
39 AreAllDumpable<T>(std::make_index_sequence<kSize>{}),
40 "One of the member of an aggregate that was marked as dumpable "
41 "with dump::IsDumpedAggregate is not dumpable. Did you forget "
42 "to include <userver/dump/common.hpp>, "
43 "<userver/dump/common_containers.hpp> or some other header with "
44 "Read and Write functions declarations?"
45 );
46 return true;
47 } else {
48 return false;
49 }
50}
51
52template <typename T, std::size_t... Indices>
53T ReadAggregate(Reader& reader, std::index_sequence<Indices...>) {
54 // `Read`s are guaranteed to occur left-to-right in brace-init
55 return T{reader.Read<boost::pfr::tuple_element_t<Indices, T>>()...};
56}
57
58} // namespace impl
59
60/// @brief Aggregates dumping support
61///
62/// To enable dumps and loads for an aggregate, add in the global namespace:
63///
64/// @code
65/// template <>
66/// struct dump::IsDumpedAggregate<MyStruct>;
67/// @endcode
68///
69/// @warning Don't forget to increment format-version if data layout changes
70template <typename T>
72 boost::pfr::for_each_field(value, [&writer](const auto& field) { writer.Write(field); });
73}
74
75/// @brief Aggregates deserialization from dump support
76///
77/// To enable dumps and loads for an aggregate, add in the global namespace:
78///
79/// @code
80/// template <>
81/// struct dump::IsDumpedAggregate<MyStruct>;
82/// @endcode
83///
84/// @warning Don't forget to increment format-version if data layout changes
85template <typename T>
87 constexpr auto kSize = boost::pfr::tuple_size_v<T>;
88 return impl::ReadAggregate<T>(reader, std::make_index_sequence<kSize>{});
89}
90
91} // namespace dump
92
93USERVER_NAMESPACE_END