MySQL 9.1.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 // clang-format off
140 Args &&... args
141 // clang-format on
142) {
143 return Codec<T>::decode(buffer, caps, std::forward<Args>(args)...);
144}
145
146namespace impl {
147
148/**
149 * Generator of decoded Types of a buffer.
150 *
151 * - .step<wire::VarInt>()
152 */
154 public:
157
158 /**
159 * construct a DecodeBufferAccumulator.
160 *
161 * @param buffer a net::const_buffer
162 * @param caps classic-protocol capabilities
163 * @param consumed bytes to skip from the buffers
164 */
166 capabilities::value_type caps, size_t consumed = 0)
167 : buffer_(buffer), caps_(caps), consumed_(consumed) {}
168
169 /**
170 * decode a Type from the buffer sequence.
171 *
172 * if it succeeds, moves position in buffer forward and returns
173 * decoded Type, otherwise returns error and updates the global error-code in
174 * result()
175 *
176 * 'sz' is unlimited, the whole rest of the current buffer
177 * is passed to the decoder.
178 *
179 * If not, a slice of size 'sz' is taken. If there isn't at least 'sz' bytes
180 * in the buffer, it fails.
181 *
182 * @param sz limits the size of the current buffer.
183 */
184 template <class T>
186 size_t sz = std::numeric_limits<size_t>::max()) {
187 if (!res_) return stdx::unexpected(res_.error());
188
189 auto step_res = step_<T>(sz);
190
191 // capture the first failure
192 if (!step_res) res_ = stdx::unexpected(step_res.error());
193
194 return step_res;
195 }
196
197 /**
198 * try decoding a Type from the buffer sequence.
199 *
200 * if it succeeds, moves position in buffer-sequence forward and returns
201 * decoded Type, otherwise returns error and does NOT update the global
202 * error-code in result()
203 */
204 template <class T>
206 size_t sz = std::numeric_limits<size_t>::max()) {
207 if (!res_) return stdx::unexpected(res_.error());
208
209 return step_<T>(sz);
210 }
211
212 /**
213 * get result of the step().
214 *
215 * if a step() failed, result is the error-code of the first failed step()
216 *
217 * @returns consumed bytes by all steps(), or error of first failed step()
218 */
220 if (!res_) return res_;
221
222 return consumed_;
223 }
224
225 private:
226 template <class T>
228 size_t sz) {
229 auto buf = buffer_ + consumed_;
230
231 if (sz != std::numeric_limits<size_t>::max()) {
232 // not enough data.
233 if (buf.size() < sz) {
235 }
236 }
237
238 auto decode_res = Codec<T>::decode(net::buffer(buf, sz), caps_);
239 if (!decode_res) return stdx::unexpected(decode_res.error());
240
241 consumed_ += decode_res->first;
242 return decode_res->second;
243 }
244
247 size_t consumed_;
248
250};
251
252/**
253 * accumulator of encoded buffers.
254 *
255 * writes the .step()ed encoded types into buffer.
256 *
257 * EncodeBufferAccumulator(buffer, caps)
258 * .step(wire::VarInt(42))
259 * .step(wire::VarInt(512))
260 * .result()
261 *
262 * The class should be used together with EncodeSizeAccumulator which shares
263 * the same interface.
264 */
266 public:
268
269 /**
270 * construct a encode-buffer-accumulator.
271 *
272 * @param buffer mutable-buffer to encode into
273 * @param caps protocol capabilities
274 * @param consumed bytes already used in the in buffer
275 */
277 capabilities::value_type caps, size_t consumed = 0)
278 : buffer_{buffer}, caps_{caps}, consumed_{consumed} {}
279
280 /**
281 * encode a T into the buffer and move position forward.
282 *
283 * no-op of a previous step failed.
284 */
285 template <class T>
287 if (!res_) return *this;
288
289 auto res = Codec<T>(v, caps_).encode(buffer_ + consumed_);
290 if (!res) { // it failed.
291 res_ = res;
292 } else {
293 consumed_ += *res;
294 }
295
296 return *this;
297 }
298
299 /**
300 * get result the steps().
301 *
302 * @returns last used position in buffer, or first error in case of a step()
303 * failed.
304 */
306 if (!res_) return res_;
307
308 return {consumed_};
309 }
310
311 private:
314 size_t consumed_{};
315
317};
318
319/**
320 * accumulates the sizes of encoded T's.
321 *
322 * e.g. the size of tw
323 *
324 * EncodeSizeAccumulator(caps)
325 * .step(wire::VarInt(42)) // 1
326 * .step(wire::VarInt(512)) // 2
327 * .result() // = 3
328 *
329 * The class should be used together with EncodeBufferAccumulator which shares
330 * the same interface.
331 */
333 public:
334 using result_type = size_t;
335
336 /**
337 * construct a EncodeSizeAccumulator.
338 */
340 : caps_{caps} {}
341
342 /**
343 * accumulate the size() of encoded T.
344 *
345 * calls Codec<T>(v, caps).size()
346 */
347 template <class T>
348 constexpr EncodeSizeAccumulator &step(const T &v) noexcept {
349 consumed_ += Codec<T>(v, caps_).size();
350
351 return *this;
352 }
353
354 /**
355 * @returns size of all steps().
356 */
357 constexpr result_type result() const { return consumed_; }
358
359 private:
360 size_t consumed_{};
362};
363
364/**
365 * CRTP base for the Codec's encode part.
366 *
367 * derived classes must provide a 'accumulate_fields()' which
368 * maps each field by the Mapper and returns the result
369 *
370 * used by .size() and .encode() as both have to process the same
371 * fields in the same order, just with different mappers
372 */
373template <class T>
375 public:
377
378 constexpr size_t size() const noexcept {
379 return static_cast<const T *>(this)->accumulate_fields(
381 }
382
385 return static_cast<const T *>(this)->accumulate_fields(
387 }
388
389 constexpr capabilities::value_type caps() const noexcept { return caps_; }
390
391 private:
393};
394
395} // namespace impl
396} // namespace classic_protocol
397
398#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:153
stdx::expected< typename Codec< T >::value_type, std::error_code > step_(size_t sz)
Definition: classic_protocol_codec_base.h:227
net::const_buffer buffer_
Definition: classic_protocol_codec_base.h:245
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:246
result_type res_
Definition: classic_protocol_codec_base.h:249
DecodeBufferAccumulator(const net::const_buffer &buffer, capabilities::value_type caps, size_t consumed=0)
construct a DecodeBufferAccumulator.
Definition: classic_protocol_codec_base.h:165
size_t consumed_
Definition: classic_protocol_codec_base.h:247
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:205
result_type result() const
get result of the step().
Definition: classic_protocol_codec_base.h:219
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:185
CRTP base for the Codec's encode part.
Definition: classic_protocol_codec_base.h:374
stdx::expected< size_t, std::error_code > encode(net::mutable_buffer buffer) const
Definition: classic_protocol_codec_base.h:383
constexpr size_t size() const noexcept
Definition: classic_protocol_codec_base.h:378
constexpr capabilities::value_type caps() const noexcept
Definition: classic_protocol_codec_base.h:389
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:392
constexpr EncodeBase(capabilities::value_type caps)
Definition: classic_protocol_codec_base.h:376
accumulator of encoded buffers.
Definition: classic_protocol_codec_base.h:265
result_type result() const
get result the steps().
Definition: classic_protocol_codec_base.h:305
EncodeBufferAccumulator & step(const T &v)
encode a T into the buffer and move position forward.
Definition: classic_protocol_codec_base.h:286
EncodeBufferAccumulator(net::mutable_buffer buffer, capabilities::value_type caps, size_t consumed=0)
construct a encode-buffer-accumulator.
Definition: classic_protocol_codec_base.h:276
const net::mutable_buffer buffer_
Definition: classic_protocol_codec_base.h:312
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:313
result_type res_
Definition: classic_protocol_codec_base.h:316
size_t consumed_
Definition: classic_protocol_codec_base.h:314
accumulates the sizes of encoded T's.
Definition: classic_protocol_codec_base.h:332
constexpr result_type result() const
Definition: classic_protocol_codec_base.h:357
constexpr EncodeSizeAccumulator(capabilities::value_type caps)
construct a EncodeSizeAccumulator.
Definition: classic_protocol_codec_base.h:339
size_t result_type
Definition: classic_protocol_codec_base.h:334
size_t consumed_
Definition: classic_protocol_codec_base.h:360
const capabilities::value_type caps_
Definition: classic_protocol_codec_base.h:361
constexpr EncodeSizeAccumulator & step(const T &v) noexcept
accumulate the size() of encoded T.
Definition: classic_protocol_codec_base.h:348
Definition: buffer.h:135
Definition: buffer.h:113
constexpr const error_type & error() const &
Definition: expected.h:760
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, Args &&... args)
decode a message from a buffer.
Definition: classic_protocol_codec_base.h:137
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
Definition: http_server_component.cc:34
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
unexpected(E) -> unexpected< E >