MySQL 9.2.0
Source Code Documentation
classic_protocol_codec_base.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_ROUTER_CLASSIC_PROTOCOL_CODEC_BASE_H_
27#define MYSQL_ROUTER_CLASSIC_PROTOCOL_CODEC_BASE_H_
28
29#include <cstddef> // size_t
30#include <cstdint> // uint8_t
31#include <limits>
32#include <system_error> // error_code
33#include <type_traits>
34#include <utility> // move
35
41
42namespace classic_protocol {
43
44// bytes needed to encode x bits
45//
46// bits | bytes
47// -----+------
48// 0 | 0
49// 1 | 1
50// ... | ...
51// 8 | 1
52// 9 | 2
53// ... | ...
54//
55constexpr size_t bytes_per_bits(size_t bits) { return (bits + 7) / 8; }
56
57static_assert(bytes_per_bits(0) == 0);
58static_assert(bytes_per_bits(1) == 1);
59static_assert(bytes_per_bits(8) == 1);
60static_assert(bytes_per_bits(9) == 2);
61
62/**
63 * Codec for a type.
64 *
65 * requirements for T:
66 * - size_t size()
67 * - stdx::expected<size_t, std::error_code> encode(net::mutable_buffer);
68 * - static stdx::expected<T, std::error_code> decode(buffer_sequence,
69 * capabilities);
70 */
71template <class T>
72class Codec;
73
74/**
75 * encode a message into a dynamic buffer.
76 *
77 * @param v message to encode
78 * @param caps protocol capabilities
79 * @param dyn_buffer dynamic buffer to write into
80 * @returns number of bytes written into dynamic buffer or std::error_code on
81 * error
82 */
83template <class T, class DynamicBuffer>
86 DynamicBuffer &&dyn_buffer) {
87 // static_assert(net::is_dynamic_buffer<DynamicBuffer>::value,
88 // "dyn_buffer MUST be a DynamicBuffer");
89
90 Codec<T> codec(v, caps);
91
92 const auto orig_size = dyn_buffer.size();
93 const auto codec_size = codec.size();
94
95 // reserve some space to write into
96 dyn_buffer.grow(codec_size);
97
98 const auto res = codec.encode(dyn_buffer.data(orig_size, codec_size));
99 if (!res) {
100 dyn_buffer.shrink(codec_size);
101 return res;
102 }
103
104 dyn_buffer.shrink(codec_size - res.value());
105
106 return res;
107}
108
109/**
110 * decode a message from a buffer.
111 *
112 * @param buffer buffer to read from
113 * @param caps protocol capabilities
114 * @tparam T the message class
115 * @returns number of bytes read from 'buffers' and a T on success, or
116 * std::error_code on error
117 */
118template <class T>
121 return Codec<T>::decode(buffer, caps);
122}
123
124/**
125 * decode a message from a buffer.
126 *
127 * @param buffer buffer to read from
128 * @param caps protocol capabilities
129 * @param args arguments that shall be forwarded to T's decode()
130 * @tparam T the message class
131 * @tparam Args Types of the extra arguments to be forwarded to T's decode()
132 * function.
133 * @returns number of bytes read from 'buffers' and a T on success, or
134 * std::error_code on error
135 */
136template <class T, class... Args>
139 Args &&...args) {
140 return Codec<T>::decode(buffer, caps, std::forward<Args>(args)...);
141}
142
143namespace impl {
144
145/**
146 * Generator of decoded Types of a buffer.
147 *
148 * - .step<wire::VarInt>()
149 */
151 public:
154
155 /**
156 * construct a DecodeBufferAccumulator.
157 *
158 * @param buffer a net::const_buffer
159 * @param caps classic-protocol capabilities
160 * @param consumed bytes to skip from the buffers
161 */
163 capabilities::value_type caps, size_t consumed = 0)
164 : buffer_(buffer), caps_(caps), consumed_(consumed) {}
165
166 /**
167 * decode a Type from the buffer sequence.
168 *
169 * if it succeeds, moves position in buffer forward and returns
170 * decoded Type, otherwise returns error and updates the global error-code in
171 * result()
172 *
173 * 'sz' is unlimited, the whole rest of the current buffer
174 * is passed to the decoder.
175 *
176 * If not, a slice of size 'sz' is taken. If there isn't at least 'sz' bytes
177 * in the buffer, it fails.
178 *
179 * @param sz limits the size of the current buffer.
180 */
181 template <class T>
183 size_t sz = std::numeric_limits<size_t>::max()) {
184 if (!res_) return stdx::unexpected(res_.error());
185
186 auto step_res = step_<T>(sz);
187
188 // capture the first failure
189 if (!step_res) res_ = stdx::unexpected(step_res.error());
190
191 return step_res;
192 }
193
194 /**
195 * try decoding a Type from the buffer sequence.
196 *
197 * if it succeeds, moves position in buffer-sequence forward and returns
198 * decoded Type, otherwise returns error and does NOT update the global
199 * error-code in result()
200 */
201 template <class T>
203 size_t sz = std::numeric_limits<size_t>::max()) {
204 if (!res_) return stdx::unexpected(res_.error());
205
206 return step_<T>(sz);
207 }
208
209 /**
210 * get result of the step().
211 *
212 * if a step() failed, result is the error-code of the first failed step()
213 *
214 * @returns consumed bytes by all steps(), or error of first failed step()
215 */
217 if (!res_) return res_;
218
219 return consumed_;
220 }
221
222 private:
223 template <class T>
225 size_t sz) {
226 auto buf = buffer_ + consumed_;
227
228 if (sz != std::numeric_limits<size_t>::max()) {
229 // not enough data.
230 if (buf.size() < sz) {
232 }
233 }
234
235 auto decode_res = Codec<T>::decode(net::buffer(buf, sz), caps_);
236 if (!decode_res) return stdx::unexpected(decode_res.error());
237
238 consumed_ += decode_res->first;
239 return decode_res->second;
240 }
241
244 size_t consumed_;
245
247};
248
249/**
250 * accumulator of encoded buffers.
251 *
252 * writes the .step()ed encoded types into buffer.
253 *
254 * EncodeBufferAccumulator(buffer, caps)
255 * .step(wire::VarInt(42))
256 * .step(wire::VarInt(512))
257 * .result()
258 *
259 * The class should be used together with EncodeSizeAccumulator which shares
260 * the same interface.
261 */
263 public:
265
266 /**
267 * construct a encode-buffer-accumulator.
268 *
269 * @param buffer mutable-buffer to encode into
270 * @param caps protocol capabilities
271 * @param consumed bytes already used in the in buffer
272 */
274 capabilities::value_type caps, size_t consumed = 0)
275 : buffer_{buffer}, caps_{caps}, consumed_{consumed} {}
276
277 /**
278 * encode a T into the buffer and move position forward.
279 *
280 * no-op of a previous step failed.
281 */
282 template <class T>
284 if (!res_) return *this;
285
286 auto res = Codec<T>(v, caps_).encode(buffer_ + consumed_);
287 if (!res) { // it failed.
288 res_ = res;
289 } else {
290 consumed_ += *res;
291 }
292
293 return *this;
294 }
295
296 /**
297 * get result the steps().
298 *
299 * @returns last used position in buffer, or first error in case of a step()
300 * failed.
301 */
303 if (!res_) return res_;
304
305 return {consumed_};
306 }
307
308 private:
311 size_t consumed_{};
312
314};
315
316/**
317 * accumulates the sizes of encoded T's.
318 *
319 * e.g. the size of tw
320 *
321 * EncodeSizeAccumulator(caps)
322 * .step(wire::VarInt(42)) // 1
323 * .step(wire::VarInt(512)) // 2
324 * .result() // = 3
325 *
326 * The class should be used together with EncodeBufferAccumulator which shares
327 * the same interface.
328 */
330 public:
331 using result_type = size_t;
332
333 /**
334 * construct a EncodeSizeAccumulator.
335 */
337 : caps_{caps} {}
338
339 /**
340 * accumulate the size() of encoded T.
341 *
342 * calls Codec<T>(v, caps).size()
343 */
344 template <class T>
345 constexpr EncodeSizeAccumulator &step(const T &v) noexcept {
346 consumed_ += Codec<T>(v, caps_).size();
347
348 return *this;
349 }
350
351 /**
352 * @returns size of all steps().
353 */
354 constexpr result_type result() const { return consumed_; }
355
356 private:
357 size_t consumed_{};
359};
360
361/**
362 * CRTP base for the Codec's encode part.
363 *
364 * derived classes must provide a 'accumulate_fields()' which
365 * maps each field by the Mapper and returns the result
366 *
367 * used by .size() and .encode() as both have to process the same
368 * fields in the same order, just with different mappers
369 */
370template <class T>
372 public:
374
375 constexpr size_t size() const noexcept {
376 return static_cast<const T *>(this)->accumulate_fields(
378 }
379
382 return static_cast<const T *>(this)->accumulate_fields(
384 }
385
386 constexpr capabilities::value_type caps() const noexcept { return caps_; }
387
388 private:
390};
391
392} // namespace impl
393} // namespace classic_protocol
394
395#endif
Codec for a type.
Definition: classic_protocol_codec_base.h:72
Generator of decoded Types of a buffer.
Definition: classic_protocol_codec_base.h:150
stdx::expected< typename Codec< T >::value_type, std::error_code > step_(size_t sz)
Definition: classic_protocol_codec_base.h:224
net::const_buffer buffer_
Definition: classic_protocol_codec_base.h:242
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:243
result_type res_
Definition: classic_protocol_codec_base.h:246
DecodeBufferAccumulator(const net::const_buffer &buffer, capabilities::value_type caps, size_t consumed=0)
construct a DecodeBufferAccumulator.
Definition: classic_protocol_codec_base.h:162
size_t consumed_
Definition: classic_protocol_codec_base.h:244
stdx::expected< typename Codec< T >::value_type, std::error_code > try_step(size_t sz=std::numeric_limits< size_t >::max())
try decoding a Type from the buffer sequence.
Definition: classic_protocol_codec_base.h:202
result_type result() const
get result of the step().
Definition: classic_protocol_codec_base.h:216
stdx::expected< typename Codec< T >::value_type, std::error_code > step(size_t sz=std::numeric_limits< size_t >::max())
decode a Type from the buffer sequence.
Definition: classic_protocol_codec_base.h:182
CRTP base for the Codec's encode part.
Definition: classic_protocol_codec_base.h:371
stdx::expected< size_t, std::error_code > encode(net::mutable_buffer buffer) const
Definition: classic_protocol_codec_base.h:380
constexpr size_t size() const noexcept
Definition: classic_protocol_codec_base.h:375
constexpr capabilities::value_type caps() const noexcept
Definition: classic_protocol_codec_base.h:386
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:389
constexpr EncodeBase(capabilities::value_type caps)
Definition: classic_protocol_codec_base.h:373
accumulator of encoded buffers.
Definition: classic_protocol_codec_base.h:262
result_type result() const
get result the steps().
Definition: classic_protocol_codec_base.h:302
EncodeBufferAccumulator & step(const T &v)
encode a T into the buffer and move position forward.
Definition: classic_protocol_codec_base.h:283
EncodeBufferAccumulator(net::mutable_buffer buffer, capabilities::value_type caps, size_t consumed=0)
construct a encode-buffer-accumulator.
Definition: classic_protocol_codec_base.h:273
const net::mutable_buffer buffer_
Definition: classic_protocol_codec_base.h:309
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:310
result_type res_
Definition: classic_protocol_codec_base.h:313
size_t consumed_
Definition: classic_protocol_codec_base.h:311
accumulates the sizes of encoded T's.
Definition: classic_protocol_codec_base.h:329
constexpr result_type result() const
Definition: classic_protocol_codec_base.h:354
constexpr EncodeSizeAccumulator(capabilities::value_type caps)
construct a EncodeSizeAccumulator.
Definition: classic_protocol_codec_base.h:336
size_t result_type
Definition: classic_protocol_codec_base.h:331
size_t consumed_
Definition: classic_protocol_codec_base.h:357
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:358
constexpr EncodeSizeAccumulator & step(const T &v) noexcept
accumulate the size() of encoded T.
Definition: classic_protocol_codec_base.h:345
Definition: buffer.h:135
Definition: buffer.h:113
constexpr const error_type & error() const &
Definition: expected.h:755
Definition: buf0block_hint.cc:30
std::bitset< 32 > value_type
Definition: classic_protocol_constants.h:73
Definition: classic_protocol_binary.h:39
stdx::expected< size_t, std::error_code > encode(const T &v, capabilities::value_type caps, DynamicBuffer &&dyn_buffer)
encode a message into a dynamic buffer.
Definition: classic_protocol_codec_base.h:84
std::error_code make_error_code(codec_errc e) noexcept
Definition: classic_protocol_codec_error.h:86
stdx::expected< std::pair< size_t, T >, std::error_code > decode(const net::const_buffer &buffer, capabilities::value_type caps)
decode a message from a buffer.
Definition: classic_protocol_codec_base.h:119
constexpr size_t bytes_per_bits(size_t bits)
Definition: classic_protocol_codec_base.h:55
stdx::expected< std::pair< size_t, T >, std::error_code > decode(const net::const_buffer &buffer, capabilities::value_type caps, Args &&...args)
decode a message from a buffer.
Definition: classic_protocol_codec_base.h:137
Definition: http_server_component.cc:34
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
unexpected(E) -> unexpected< E >