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> &&
37 !meta::kIsDetected<IsNotDumpedAggregate, T>) {
38 constexpr auto kSize = boost::pfr::tuple_size_v<T>;
39 static_assert(
40 AreAllDumpable<T>(std::make_index_sequence<kSize>{}),
41 "One of the member of an aggregate that was marked as dumpable "
42 "with dump::IsDumpedAggregate is not dumpable. Did you forget "
43 "to include <userver/dump/common.hpp>, "
44 "<userver/dump/common_containers.hpp> or some other header with "
45 "Read and Write functions declarations?");
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 const T& value) {
73 boost::pfr::for_each_field(
74 value, [&writer](const auto& field) { writer.Write(field); });
75}
76
77/// @brief Aggregates deserialization from dump support
78///
79/// To enable dumps and loads for an aggregate, add in the global namespace:
80///
81/// @code
82/// template <>
83/// struct dump::IsDumpedAggregate<MyStruct>;
84/// @endcode
85///
86/// @warning Don't forget to increment format-version if data layout changes
87template <typename T>
89 To<T>) {
90 constexpr auto kSize = boost::pfr::tuple_size_v<T>;
91 return impl::ReadAggregate<T>(reader, std::make_index_sequence<kSize>{});
92}
93
94} // namespace dump
95
96USERVER_NAMESPACE_END