Bond
 
All Classes Namespaces Files Functions Variables Typedefs Friends Pages
Loading...
Searching...
No Matches
simple_binary.h
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#pragma once
5
6#include <bond/core/config.h>
7
8#include "encoding.h"
9
10#include <bond/core/bond_version.h>
11#include <bond/core/traits.h>
12
13#include <boost/call_traits.hpp>
14#include <boost/noncopyable.hpp>
15
16/*
17 .-------------.----------------.
18 struct | base fields | derived fields |
19 '-------------'----------------'
20
21 .----------.----------. .----------.
22 fields | field | field |...| field |
23 '----------'----------' '----------'
24
25 .----------.
26 field | value |
27 '----------'
28
29 .---.---.---.---.---.---.---.---.
30 value bool | | | | | | | | v |
31 '---'---'---'---'---'---'---'---'
32 0
33
34 all integral types are written binary, native size, uncompressed, little endian
35
36 float, double little endian
37
38
39 .-------.------------.
40 string, wstring | count | characters |
41 '-------'------------'
42
43 count uint32 count of 1-byte (for string)
44 or 2-byte (for wstring) Unicode code
45 units (variable encoded in v2)
46
47 characters 1-byte UTF-8 code units (for string) or 2-byte
48 UTF-16LE code units (for wstring)
49
50
51 .-------. .-------.
52 blob, list, set, | count | | items |...
53 vector, nullable '-------' '-------'
54
55 count uint32 count of items (variable encoded in v2)
56
57 items each item encoded according to its type
58
59 .-------. .-----.--------.
60 map | count | | key | mapped |...
61 '-------' '-----'--------'
62
63 count uint32 count of {key,mapped} pairs (variable encoded in v2)
64
65 key, mapped each item encoded according to its type
66
67 .-------. .-----------.
68 bonded | count | | marshaled |
69 '-------' '-----------'
70 count uint32 count of bytes (always fixed-width, even in v2)
71
72 marshaled a marshaled payload
73*/
74
75namespace bond
76{
77
78
79template <typename BufferT>
81
82
84template <typename BufferT, typename MarshaledBondedProtocolsT>
86{
87public:
88 typedef BufferT Buffer;
89 typedef StaticParser<SimpleBinaryReader&> Parser;
90 typedef SimpleBinaryWriter<Buffer> Writer;
91
92 BOND_STATIC_CONSTEXPR uint16_t magic = SIMPLE_PROTOCOL;
93 BOND_STATIC_CONSTEXPR uint16_t version = v2;
94
95
97 SimpleBinaryReader(typename boost::call_traits<Buffer>::param_type input,
98 uint16_t version_value = default_version<SimpleBinaryReader>::value)
99 : _input(input),
100 _version(version_value)
101 {
102 BOOST_ASSERT(_version <= SimpleBinaryReader::version);
103 }
104
105
106 // This identical to compiler generated ctor except for noexcept declaration.
107 // Copy ctor that is explicitly declared throw() is needed for boost::variant
108 // to use optimized code path.
110 SimpleBinaryReader(const SimpleBinaryReader& that) BOND_NOEXCEPT
111 : _input(that._input),
112 _version(that._version)
113 {}
114
115
117 bool operator==(const SimpleBinaryReader& rhs) const
118 {
119 return _input == rhs._input;
120 }
121
122
124 typename boost::call_traits<Buffer>::const_reference
125 GetBuffer() const
126 {
127 return _input;
128 }
129
130
132 typename boost::call_traits<Buffer>::reference
134 {
135 return _input;
136 }
137
138
139 bool ReadVersion()
140 {
141 uint16_t magic_value;
142
143 _input.Read(magic_value);
144 _input.Read(_version);
145
146 return magic_value == SimpleBinaryReader::magic
147 && _version <= SimpleBinaryReader::version;
148 }
149
150
151 // Read for basic types
152 template <typename T>
153 typename boost::disable_if<is_string_type<T> >::type
154 Read(T& var)
155 {
156 _input.Read(var);
157 }
158
159
160 // Read for strings
161 template <typename T>
162 typename boost::enable_if<is_string_type<T> >::type
163 Read(T& var)
164 {
165 uint32_t length = 0;
166
167 ReadSize(length);
168
169 constexpr uint8_t charSize = static_cast<uint8_t>(sizeof(typename detail::string_char_int_type<T>::type));
170 uint32_t numStringBytes = detail::checked_multiply(length, charSize);
171 if (!_input.CanRead(numStringBytes))
172 {
173 OutOfBoundStringSizeException();
174 }
175
176 detail::ReadStringData(_input, var, length);
177 }
178
179
180 // Read for blob
181 void Read(blob& var, uint32_t size)
182 {
183 _input.Read(var, size);
184 }
185
186 // Does the reader have enough input buffer left to read an array of T?
187 template<typename T>
188 bool CanReadArray(uint32_t num_elems)
189 {
190 // We need to silence MSVC's warning about constant conditional expression. This
191 // construct could be replaced with explicit template specialization, but that is
192 // not possible due to gcc's bug (https://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#727).
193#ifdef _MSC_VER
194#pragma warning(push)
195#pragma warning(disable:4127)
196#endif
197
198 BOND_IF_CONSTEXPR(is_string_type<T>::value)
199 {
200 BOND_IF_CONSTEXPR(version == v1)
201 {
202 // In v1, strings encode their length as uin32 in 4 Bytes, so we multiply num_elems.
203 return _input.CanRead(detail::checked_multiply(num_elems, 4));
204 }
205 else
206 {
207 // In v2, strings use variable-length encoded integers to specify length, 1 Byte each
208 // ix their minumum length each.
209 return _input.CanRead(num_elems);
210 }
211 }
212 else BOND_IF_CONSTEXPR(boost::is_same<T, bool>::value)
213 {
214 // booleans are encoded as 1 Byte
215 return _input.CanRead(num_elems);
216 }
217 else
218 {
219 // We will need to read num_elems instances of T. This will not overflow because
220 // num_elems < 2^32 and we call this only for primitive types, so sizeof(T) <= 8.
221 uint64_t num_bytes = static_cast<uint64_t>(num_elems) * sizeof(T);
222
223 // Check if num_bytes is 32-bit as the Reader cannot grab more than that
224 return (num_bytes >> 32 == 0) && _input.CanRead(num_bytes & 0xffffffff);
225 }
226
227#ifdef _MSC_VER
228#pragma warning(pop)
229#endif
230
231 }
232
233 // Skip for basic types
234 template <typename T>
235 typename boost::disable_if<is_string_type<T> >::type
236 Skip()
237 {
238 _input.Skip(sizeof(T));
239 }
240
241
242 template <typename T>
243 void Skip(const bonded<T, SimpleBinaryReader&>& bonded);
244
245
246 // Skip for strings
247 template <typename T>
248 typename boost::enable_if<is_string_type<T> >::type
249 Skip()
250 {
251 uint32_t length;
252
253 ReadSize(length);
254 _input.Skip(length * sizeof(typename detail::string_char_int_type<T>::type));
255 }
256
257
258 void Skip(BondDataType type)
259 {
260 switch (type)
261 {
262 case BT_BOOL:
263 case BT_UINT8:
264 case BT_INT8:
265 _input.Skip(sizeof(uint8_t));
266 break;
267
268 case BT_UINT16:
269 case BT_INT16:
270 _input.Skip(sizeof(uint16_t));
271 break;
272
273 case BT_UINT32:
274 case BT_INT32:
275 _input.Skip(sizeof(uint32_t));
276 break;
277
278 case BT_UINT64:
279 case BT_INT64:
280 _input.Skip(sizeof(uint64_t));
281 break;
282
283 case BT_FLOAT:
284 _input.Skip(sizeof(float));
285 break;
286
287 case BT_DOUBLE:
288 _input.Skip(sizeof(double));
289 break;
290
291 case BT_STRING:
292 Skip<std::string>();
293 break;
294
295 case BT_WSTRING:
296 Skip<std::wstring>();
297 break;
298
299 default:
300 break;
301 }
302 }
303
304
305 template <typename T>
306 void ReadContainerBegin(uint32_t& size, T&)
307 {
308 ReadSize(size);
309 }
310
311 void ReadContainerEnd()
312 {}
313
314protected:
315 void ReadSize(uint32_t& size)
316 {
317 if (_version == v1)
318 Read(size);
319 else
320 ReadVariableUnsigned(_input, size);
321 }
322
323
324 template <typename Input, typename MarshaledBondedProtocols, typename Output>
325 friend
326 bool is_protocol_version_same(const SimpleBinaryReader<Input, MarshaledBondedProtocols>&,
327 const SimpleBinaryWriter<Output>&);
328
329 Buffer _input;
330 uint16_t _version;
331};
332
333
334template <typename BufferT, typename MarshaledBondedProtocolsT>
335BOND_CONSTEXPR_OR_CONST uint16_t SimpleBinaryReader<BufferT, MarshaledBondedProtocolsT>::magic;
336
337
339template <typename BufferT>
341 : boost::noncopyable
342{
343public:
344 typedef BufferT Buffer;
345 typedef SimpleBinaryReader<Buffer> Reader;
346
348 SimpleBinaryWriter(Buffer& output,
349 uint16_t version = default_version<Reader>::value)
350 : _output(output),
351 _version(version)
352 {
353 BOOST_ASSERT(_version <= Reader::version);
354 }
355
357 typename boost::call_traits<Buffer>::reference
359 {
360 return _output;
361 }
362
363 void WriteVersion()
364 {
365 _output.Write(Reader::magic);
366 _output.Write(_version);
367 }
368
369 void WriteStructBegin(const Metadata& /*metadata*/, bool /*base*/)
370 {}
371
372 void WriteStructEnd(bool = false)
373 {}
374
375 void WriteFieldBegin(BondDataType /*type*/, uint16_t /*id*/, const Metadata& /*metadata*/)
376 {}
377
378 void WriteFieldBegin(BondDataType /*type*/, uint16_t /*id*/)
379 {}
380
381 void WriteFieldEnd()
382 {}
383
384
385 // WriteContainerBegin
386 template <typename T>
387 void WriteContainerBegin(uint32_t size, T)
388 {
389 WriteSize(size);
390 }
391
392
393 // WriteContainerEnd
394 void WriteContainerEnd()
395 {}
396
397 template <typename T>
398 void WriteField(uint16_t /*id*/, const bond::Metadata& /*metadata*/, const T& value)
399 {
400 Write(value);
401 }
402
403 void WriteFieldOmitted(BondDataType type, uint16_t /*id*/, const Metadata& metadata);
404
405 // Write for basic types
406 template <typename T>
407 typename boost::disable_if<is_string_type<T> >::type
408 Write(const T& value)
409 {
410 _output.Write(value);
411 }
412
413 // Write for strings
414 template <typename T>
415 typename boost::enable_if<is_string_type<T> >::type
416 Write(const T& value)
417 {
418 uint32_t length = string_length(value);
419
420 WriteSize(length);
421 detail::WriteStringData(_output, value, length);
422 }
423
424 // Write for blob
425 void Write(const blob& value)
426 {
427 _output.Write(value);
428 }
429
430protected:
431 void WriteSize(uint32_t& size)
432 {
433 if (_version == v1)
434 Write(size);
435 else
436 WriteVariableUnsigned(_output, size);
437 }
438
439 template <typename Input, typename MarshaledBondedProtocols, typename Output>
440 friend
441 bool is_protocol_version_same(const SimpleBinaryReader<Input, MarshaledBondedProtocols>&,
443
444 Buffer& _output;
445 uint16_t _version;
446};
447
448
449template <typename Input, typename MarshaledBondedProtocols> struct
450protocol_has_multiple_versions<SimpleBinaryReader<Input, MarshaledBondedProtocols> >
451 : std::true_type {};
452
453
454template <typename Input, typename MarshaledBondedProtocols, typename Output>
455bool is_protocol_version_same(const SimpleBinaryReader<Input, MarshaledBondedProtocols>& reader,
456 const SimpleBinaryWriter<Output>& writer)
457{
458 return reader._version == writer._version;
459}
460
461template <typename Output> struct
462may_omit_fields<SimpleBinaryWriter<Output> >
463 : std::false_type {};
464
465} // namespace bond
Reader for Simple Binary protocol.
Definition simple_binary.h:86
boost::call_traits< Buffer >::const_reference GetBuffer() const
Access to underlying buffer.
Definition simple_binary.h:125
SimpleBinaryReader(typename boost::call_traits< Buffer >::param_type input, uint16_t version_value=default_version< SimpleBinaryReader >::value)
Construct from input buffer/stream containing serialized data.
Definition simple_binary.h:97
bool operator==(const SimpleBinaryReader &rhs) const
Comparison operator.
Definition simple_binary.h:117
SimpleBinaryReader(const SimpleBinaryReader &that) BOND_NOEXCEPT
Copy constructor.
Definition simple_binary.h:110
boost::call_traits< Buffer >::reference GetBuffer()
Access to underlying buffer.
Definition simple_binary.h:133
Writer for Simple Binary protocol.
Definition simple_binary.h:342
boost::call_traits< Buffer >::reference GetBuffer()
Access to underlying buffer.
Definition simple_binary.h:358
SimpleBinaryWriter(Buffer &output, uint16_t version=default_version< Reader >::value)
Construct from output buffer/stream.
Definition simple_binary.h:348
namespace bond
Definition apply.h:17