userver: userver/dump/operations.hpp Source File
Loading...
Searching...
No Matches
operations.hpp
1#pragma once
2
3#include <stdexcept>
4#include <string>
5#include <string_view>
6#include <type_traits>
7
8#include <userver/dump/fwd.hpp>
9#include <userver/dump/meta.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace dump {
14
15/// Indicates a failure reading or writing a dump. No further operations
16/// should be performed with a failed dump.
17class Error final : public std::runtime_error {
18 public:
19 explicit Error(std::string message) : std::runtime_error(message) {}
20};
21
22/// A general interface for binary data output
23class Writer {
24 public:
25 virtual ~Writer() = default;
26
27 /// @brief Writes binary data
28 /// @details Calls ADL-found `Write(writer, data)`
29 /// @throws `Error` and any user-thrown `std::exception`
30 template <typename T>
31 void Write(const T& data);
32
33 /// @brief Must be called once all data has been written
34 /// @warning This method must not be called from within `Write`/`Read`
35 /// @throws `Error` on write operation failure
36 virtual void Finish() = 0;
37
38 protected:
39 /// @brief Writes binary data
40 /// @details Unlike `Write`, doesn't write the size of `data`
41 /// @throws `Error` on write operation failure
42 virtual void WriteRaw(std::string_view data) = 0;
43
44 friend void WriteStringViewUnsafe(Writer& writer, std::string_view value);
45};
46
47/// A general interface for binary data input
48class Reader {
49 public:
50 virtual ~Reader() = default;
51
52 /// @brief Reads binary data
53 /// @details Calls ADL-found `Read(reader, To<T>)`
54 /// @throws `Error` and any user-thrown `std::exception`
55 template <typename T>
56 T Read();
57
58 /// @brief Must be called once all data has been read
59 /// @warning This method must not be called from within `Write`/`Read`
60 /// @throws `Error` on read operation failure or if there is leftover data
61 virtual void Finish() = 0;
62
63 protected:
64 /// @brief Reads binary data
65 /// @note Invalidates the memory returned by the previous call of `ReadRaw`
66 /// @note Normally, exactly `max_size` bytes is returned. On end-of-file,
67 /// the amount of bytes returned can be less than `max_size`.
68 /// @throws `Error` on read operation failure
70
72};
73
74namespace impl {
75
76template <typename T>
77void CallWrite(Writer& writer, const T& data) {
78 Write(writer, data);
79}
80
81template <typename T>
82// NOLINTNEXTLINE(readability-const-return-type)
83T CallRead(Reader& reader, To<T> to) {
84 return Read(reader, to);
85}
86
87} // namespace impl
88
89template <typename T>
90void Writer::Write(const T& data) {
91 if constexpr (kIsWritable<T>) {
92 impl::CallWrite(*this, data);
93 } else if constexpr (std::is_aggregate_v<T>) {
94 static_assert(
95 !sizeof(T),
96 "Serialization is not implemented for this type. You "
97 "either forgot to specialize IsDumpedAggregate for your type "
98 "(see <userver/dump/aggregates.hpp>)"
99 "or you've got a non-standard data type and need to implement "
100 "`void Write(dump::Writer& writer, const T& data);` and put it "
101 "in the namespace of `T` or in `dump`.");
102 } else {
103 static_assert(
104 !sizeof(T),
105 "You either forgot to `#include <userver/dump/common_containers.hpp>`, "
106 "or you've got a non-standard data type and need to implement "
107 "`void Write(dump::Writer& writer, const T& data);` and put it "
108 "in the namespace of `T` or in `dump`.");
109 }
110}
111
112template <typename T>
113// NOLINTNEXTLINE(readability-const-return-type)
114T Reader::Read() {
115 if constexpr (kIsReadable<T>) {
116 return impl::CallRead(*this, To<T>{});
117 } else if constexpr (std::is_aggregate_v<T>) {
118 static_assert(
119 !sizeof(T),
120 "Serialization is not implemented for this type. You "
121 "either forgot to specialize IsDumpedAggregate for your type"
122 "(see <userver/dump/aggregates.hpp>) "
123 "or you've got a non-standard data type and need to implement "
124 "`T Read(dump::Reader& reader, dump::To<T>);` and put it "
125 "in the namespace of `T` or in `dump`.");
126 } else {
127 static_assert(
128 !sizeof(T),
129 "You either forgot to `#include <userver/dump/common_containers.hpp>`, "
130 "or you've got a non-standard data type and need to implement"
131 "`T Read(dump::Reader& reader, dump::To<T>);` and put it "
132 "in the namespace of `T` or in `dump`.");
133 return T{};
134 }
135}
136
137} // namespace dump
138
139USERVER_NAMESPACE_END