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 {
18public:
19 explicit Error(std::string message) : std::runtime_error(message) {}
20};
21
22/// A general interface for binary data output
23class Writer {
24public:
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
38protected:
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 {
49public:
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
63protected:
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 );
103 } else {
104 static_assert(
105 !sizeof(T),
106 "You either forgot to `#include <userver/dump/common_containers.hpp>`, "
107 "or you've got a non-standard data type and need to implement "
108 "`void Write(dump::Writer& writer, const T& data);` and put it "
109 "in the namespace of `T` or in `dump`."
110 );
111 }
112}
113
114template <typename T>
115// NOLINTNEXTLINE(readability-const-return-type)
116T Reader::Read() {
117 if constexpr (kIsReadable<T>) {
118 return impl::CallRead(*this, To<T>{});
119 } else if constexpr (std::is_aggregate_v<T>) {
120 static_assert(
121 !sizeof(T),
122 "Serialization is not implemented for this type. You "
123 "either forgot to specialize IsDumpedAggregate for your type"
124 "(see <userver/dump/aggregates.hpp>) "
125 "or you've got a non-standard data type and need to implement "
126 "`T Read(dump::Reader& reader, dump::To<T>);` and put it "
127 "in the namespace of `T` or in `dump`."
128 );
129 } else {
130 static_assert(
131 !sizeof(T),
132 "You either forgot to `#include <userver/dump/common_containers.hpp>`, "
133 "or you've got a non-standard data type and need to implement"
134 "`T Read(dump::Reader& reader, dump::To<T>);` and put it "
135 "in the namespace of `T` or in `dump`."
136 );
137 return T{};
138 }
139}
140
141} // namespace dump
142
143USERVER_NAMESPACE_END