Line data Source code
1 : #pragma once
2 :
3 : // This component provides encoding routines for [MessagePack][1].
4 : //
5 : // Each function is in `namespace msgpack` and appends a specified value to a
6 : // `std::string`. For example, `msgpack::pack_integer(destination, -42)`
7 : // MessagePack encodes the number `-42` and appends the result to `destination`.
8 : //
9 : // Only encoding is provided, and only for the types required by `SpanData` and
10 : // `DatadogAgent`.
11 : //
12 : // [1]: https://msgpack.org/index.html
13 :
14 : #include <climits>
15 : #include <cstddef>
16 : #include <cstdint>
17 : #include <string>
18 : #include <utility>
19 :
20 : #include "expected.h"
21 : #include "string_view.h"
22 :
23 : namespace datadog {
24 : namespace tracing {
25 : namespace msgpack {
26 :
27 : void pack_integer(std::string& buffer, std::int64_t value);
28 : void pack_integer(std::string& buffer, std::uint64_t value);
29 : void pack_integer(std::string& buffer, std::int32_t value);
30 :
31 : void pack_double(std::string& buffer, double value);
32 :
33 : Expected<void> pack_string(std::string& buffer, StringView value);
34 : Expected<void> pack_string(std::string& buffer, const char* begin,
35 : std::size_t size);
36 :
37 : Expected<void> pack_array(std::string& buffer, std::size_t size);
38 :
39 : // Append to the specified `buffer` a MessagePack encoded array having the
40 : // specified `values`, where for each element of `values` the specified
41 : // `pack_value` function appends the value. `pack_value` is invoked with two
42 : // arguments: the first is a reference to `buffer`, and the second is a
43 : // reference to the current value. `pack_value` returns an `Expected<void>`. If
44 : // the return value is an error, then iteration is halted and the error is
45 : // returned. If some other error occurs, then an error is returned. Otherwise,
46 : // the non-error value is returned.
47 : template <typename Iterable, typename PackValue>
48 : Expected<void> pack_array(std::string& buffer, Iterable&& values,
49 : PackValue&& pack_value);
50 :
51 : Expected<void> pack_map(std::string& buffer, std::size_t size);
52 :
53 : // Append to the specified `buffer` a MessagePack encoded map consisting of the
54 : // specified `pairs`, where the first element of each pair is the name of the
55 : // map element, and the second element of each pair is some value that is
56 : // MessagePack encoded by the specified `pack_value` function. `pack_value` is
57 : // invoked with two arguments: the first is a reference to `buffer`, and the
58 : // second is a reference to the current value. `pack_value` returns an
59 : // `Expected<void>`. If the return value is an error, then iteration is halted
60 : // and the error is returned. If some other error occurs, then an error is
61 : // returned. Otherwise, the non-error value is returned.
62 : template <typename PairIterable, typename PackValue>
63 : Expected<void> pack_map(std::string& buffer, const PairIterable& pairs,
64 : PackValue&& pack_value);
65 :
66 : // Append to the specified `buffer` a MessagePack encoded map consisting of the
67 : // specified key value pairs. After the `buffer` argument, `pack_map` accepts
68 : // an even number of arguments. First in each pair of arguments is `key`, the
69 : // key name of the corresponding map item. Second in each pair of arguments is
70 : // `pack_value`, a function that encodes the corresponding value. `pack_value`
71 : // is invoked with one argument: a reference to `buffer`. `pack_value` returns
72 : // an `Expected<void>`. If the return value is an error, then iteration is
73 : // halted and the error is returned. If some other error occurs, then an error
74 : // is returned. Otherwise, the non-error value is returned.
75 : template <typename PackValue, typename... Rest>
76 : Expected<void> pack_map(std::string& buffer, StringView key,
77 : PackValue&& pack_value, Rest&&... rest);
78 :
79 : template <typename PackValue, typename... Rest>
80 : Expected<void> pack_map_suffix(std::string& buffer, StringView key,
81 : PackValue&& pack_value, Rest&&... rest);
82 : Expected<void> pack_map_suffix(std::string& buffer);
83 :
84 : template <typename Iterable, typename PackValue>
85 838 : Expected<void> pack_array(std::string& buffer, Iterable&& values,
86 : PackValue&& pack_value) {
87 838 : Expected<void> result;
88 838 : result = pack_array(buffer, std::size(values));
89 838 : if (!result) {
90 1 : return result;
91 : }
92 1674 : for (const auto& value : values) {
93 838 : result = pack_value(buffer, value);
94 838 : if (!result) {
95 1 : break;
96 : }
97 : }
98 837 : return result;
99 0 : }
100 :
101 : template <typename PairIterable, typename PackValue>
102 840 : Expected<void> pack_map(std::string& buffer, const PairIterable& pairs,
103 : PackValue&& pack_value) {
104 840 : Expected<void> result;
105 840 : result = pack_map(buffer, std::size(pairs));
106 840 : if (!result) {
107 1 : return result;
108 : }
109 3757 : for (const auto& [key, value] : pairs) {
110 2919 : result = pack_string(buffer, key);
111 2919 : if (!result) {
112 0 : break;
113 : }
114 2919 : result = pack_value(buffer, value);
115 2919 : if (!result) {
116 1 : break;
117 : }
118 : }
119 839 : return result;
120 0 : }
121 :
122 : template <typename PackValue, typename... Rest>
123 420 : Expected<void> pack_map(std::string& buffer, StringView key,
124 : PackValue&& pack_value, Rest&&... rest) {
125 : static_assert(
126 : sizeof...(rest) % 2 == 0,
127 : "pack_map must receive an even number of arguments after the first.");
128 : static_assert(
129 : sizeof...(rest) / 2 <= UINT32_MAX,
130 : "You're passing more than eight billion arguments to a function.");
131 420 : (void)pack_map(buffer, 1 + sizeof...(rest) / 2);
132 :
133 : return pack_map_suffix(buffer, key, std::forward<PackValue>(pack_value),
134 420 : std::forward<Rest>(rest)...);
135 : }
136 :
137 : template <typename PackValue, typename... Rest>
138 5030 : Expected<void> pack_map_suffix(std::string& buffer, StringView key,
139 : PackValue&& pack_value, Rest&&... rest) {
140 5030 : Expected<void> result;
141 5030 : result = pack_string(buffer, key);
142 5030 : if (!result) {
143 0 : return result;
144 : }
145 5030 : result = pack_value(buffer);
146 5030 : if (!result) {
147 1 : return result;
148 : }
149 5029 : result = pack_map_suffix(buffer, std::forward<Rest>(rest)...);
150 5029 : return result;
151 0 : }
152 :
153 419 : inline Expected<void> pack_map_suffix(std::string&) {
154 : // base case does nothing
155 419 : return {};
156 : }
157 :
158 419 : inline void pack_integer(std::string& buffer, std::int32_t value) {
159 419 : pack_integer(buffer, std::int64_t(value));
160 419 : }
161 :
162 11294 : inline Expected<void> pack_string(std::string& buffer, StringView value) {
163 11294 : return pack_string(buffer, value.begin(), value.size());
164 : }
165 :
166 : } // namespace msgpack
167 : } // namespace tracing
168 : } // namespace datadog
|