userver: userver/dump/aggregates.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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