Bond
 
Loading...
Searching...
No Matches
value.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#include <bond/core/detail/recursionguard.h>
8#include "bonded.h"
9#include "protocol.h"
10#include "schema.h"
11#include "detail/typeid_value.h"
12
13#include <boost/static_assert.hpp>
14
15namespace bond
16{
17
18namespace detail
19{
20
21template <typename X, typename T>
22typename boost::disable_if<is_type_alias<X> >::type
23inline set(X& var, const T& value)
24{
25 BOOST_STATIC_ASSERT((is_matching_basic<T, X>::value));
26 var = static_cast<X>(value);
27}
28
29
30template <typename X, typename T>
31typename boost::enable_if<is_type_alias<X> >::type
32inline set(X& var, const T& value)
33{
34 BOOST_STATIC_ASSERT((is_matching_basic<T, X>::value));
35 set_aliased_value(var, value);
36}
37
38
39} // namespace detail
40
41
42template <typename X, typename T>
43inline X cast(const T& value)
44{
45 X x;
46 detail::set(x, value);
47 return x;
48}
49
50
51// Skip basic type
52template <typename T, typename Reader>
53typename boost::enable_if<is_basic_type<T> >::type
54inline Skip(Reader& input)
55{
56 input.template Skip<T>();
57}
58
59
60// Skip Bond struct
61template <typename T, typename Reader>
62typename boost::enable_if<is_bond_type<T> >::type
63inline Skip(Reader& input)
64{
65 bonded<T, Reader&>(input).Skip();
66}
67
68
69// Skip container for static parser
70template <typename T, typename Reader>
71typename boost::enable_if_c<is_container<T>::value &&
72 uses_static_parser<Reader>::value>::type
73inline Skip(Reader& input)
74{
75 SkipContainer(value<typename element_type<T>::type, Reader&>(input, false), input);
76}
77
78
79// Skip by type id for static parser
80template <typename Reader>
81typename boost::enable_if<uses_static_parser<Reader> >::type
82inline Skip(Reader& input, const RuntimeSchema& schema)
83{
84 switch (schema.GetTypeId())
85 {
86 case bond::BT_SET:
87 case bond::BT_LIST:
88 {
89 return SkipContainer(
90 value<void, Reader&>(input, element_schema(schema), false), input);
91 }
92 case bond::BT_MAP:
93 {
94 return SkipMap(key_schema(schema).GetTypeId(),
95 value<void, Reader&>(input, element_schema(schema), false), input);
96 }
97 case bond::BT_STRUCT:
98 {
99 return bonded<void, Reader&>(input, schema).Skip();
100 }
101 default:
102 {
103 return input.Skip(schema.GetTypeId());
104 }
105 }
106}
107
108template <typename Reader>
109typename boost::enable_if<uses_static_parser<Reader> >::type
110inline Skip(Reader&, BondDataType)
111{
112 BOOST_ASSERT(false);
113}
114
115
116// Skip list for dynamic parser
117template <typename T, typename Reader>
118typename boost::enable_if_c<is_container<T>::value &&
119 !uses_static_parser<Reader>::value>::type
120inline Skip(Reader& input)
121{
122 // Call protocol to skip containers; this allows protocols to implement
123 // more efficient skipping than element-by-element
124 input.template Skip<T>();
125}
126
127
128// Skip by type id for dynamic parser
129template <typename Reader>
130typename boost::disable_if<uses_static_parser<Reader> >::type
131inline Skip(Reader& input, const RuntimeSchema& schema)
132{
133 input.Skip(schema.GetTypeId());
134}
135
136template <typename Reader>
137typename boost::disable_if<uses_static_parser<Reader> >::type
138inline Skip(Reader& input, BondDataType type)
139{
140 input.Skip(type);
141}
142
143
144template <typename T, typename Reader>
145BOND_NO_INLINE void Skip(Reader& input, const std::nothrow_t&) BOND_NOEXCEPT
146{
147 try
148 {
149 Skip<T>(input);
150 }
151 catch(...)
152 {}
153}
154
155template <typename T, typename Reader = SchemaReader, typename boost::enable_if<std::is_same<Reader, SchemaReader> >::type* = nullptr>
156void Skip(SchemaReader&, const std::nothrow_t&) BOND_NOEXCEPT
157{}
158
159template <typename Reader>
160BOND_NO_INLINE void Skip(Reader& input, const RuntimeSchema& schema, const std::nothrow_t&) BOND_NOEXCEPT
161{
162 try
163 {
164 Skip(input, schema);
165 }
166 catch(...)
167 {}
168}
169
170inline void Skip(SchemaReader&, const RuntimeSchema&, const std::nothrow_t&) BOND_NOEXCEPT
171{}
172
173template <typename Reader>
174BOND_NO_INLINE void Skip(Reader& input, BondDataType type, const std::nothrow_t&) BOND_NOEXCEPT
175{
176 try
177 {
178 Skip(input, type);
179 }
180 catch(...)
181 {}
182}
183
184inline void Skip(SchemaReader&, BondDataType, const std::nothrow_t&) BOND_NOEXCEPT
185{}
186
187
188// value_common implements common functionality related to skipping unread values
189template <typename T, typename Reader>
190class value_common
191 : detail::nonassignable
192{
193public:
194 value_common(Reader input, bool skip)
195 : _input(input),
196 _skip(skip)
197 {}
198
199 value_common(value_common&& rhs) BOND_NOEXCEPT_IF(
200 BOND_NOEXCEPT_EXPR(detail::move_data<Reader>(rhs._input)))
201 : _input(detail::move_data<Reader>(rhs._input)),
202 _skip(std::move(rhs._skip))
203 {
204 rhs._skip = false;
205 }
206
207 value_common(const value_common& that) = default;
208 value_common& operator=(const value_common& that) = default;
209
210 ~value_common()
211 {
212 // skip the value if it has not been read
213 if (_skip)
214 bond::Skip<T, typename std::remove_reference<Reader>::type>(_input, std::nothrow);
215 }
216
217 void Skip() const
218 {
219 _skip = false;
220 bond::Skip<T, typename std::remove_reference<Reader>::type>(_input);
221 }
222
223 // skip value of non-matching type
224 template <typename Protocols = BuiltInProtocols, typename X>
225 void Deserialize(X& /*var*/, typename boost::disable_if<is_matching<T, X> >::type* = nullptr) const
226 {
227 Skip();
228 }
229
230
231protected:
232 Reader _input;
233 mutable bool _skip;
234};
235
236
237// Specialization of value for basic types
239template <typename T, typename Reader>
240class value<T, Reader, typename boost::enable_if_c<is_basic_type<T>::value && !is_type_alias<T>::value>::type>
241 : public value_common<T, Reader>
242{
243public:
244 value(Reader input, bool skip = true)
245 : value_common<T, Reader>(input, skip)
246 {}
247
248 value(value&& rhs) BOND_NOEXCEPT_IF((
249 std::is_nothrow_move_constructible<value_common<T, Reader> >::value))
250 : value_common<T, Reader>(std::move(rhs))
251 {}
252
253 value(const value& that) = default;
254 value& operator=(const value& that) = default;
255
257 template <typename Protocols = BuiltInProtocols>
258 void Deserialize(T& var) const
259 {
260 _skip = false;
261 _input.Read(var);
262 }
263
264
265 // deserialize series of matching values to blob
266 template <typename Protocols = BuiltInProtocols>
267 void Deserialize(blob& var, uint32_t size) const
268 {
269 BOOST_STATIC_ASSERT((std::is_same<T, blob::value_type>::value));
270 _skip = false;
271 _input.Read(var, size);
272 }
273
274
275 // deserialize the value and cast it to a variable of a matching non-string type
276 template <typename Protocols = BuiltInProtocols, typename X>
277 typename boost::enable_if_c<is_matching_basic<T, X>::value && !is_string_type<T>::value>::type
278 Deserialize(X& var) const
279 {
280 typename std::conditional<std::is_enum<X>::value && sizeof(X) == sizeof(T), X, T>::type data;
281
282 _skip = false;
283 _input.Read(data);
284 detail::set(var, data);
285 }
286
287
288 // deserialize the value to a variable of a matching string type
289 template <typename Protocols = BuiltInProtocols, typename X>
290 typename boost::enable_if_c<is_matching_basic<T, X>::value && is_string_type<T>::value>::type
291 Deserialize(X& var) const
292 {
293 _skip = false;
294 _input.Read(var);
295 }
296
297
298 using value_common<T, Reader>::Deserialize;
299
300protected:
301 using value_common<T, Reader>::_input;
302 using value_common<T, Reader>::_skip;
303};
304
305
306// Specialization of value for type alias
307template <typename T, typename Reader>
308class value<T, Reader, typename boost::enable_if<is_type_alias<T> >::type>
309 : public value_common<T, Reader>
310{
311public:
312 value(Reader input, bool skip = true)
313 : value_common<T, Reader>(input, skip)
314 {}
315
316 value(value&& rhs) BOND_NOEXCEPT_IF((
317 std::is_nothrow_move_constructible<value_common<T, Reader> >::value))
318 : value_common<T, Reader>(std::move(rhs))
319 {}
320
321 value(const value& that) = default;
322 value& operator=(const value& that) = default;
323
324 template <typename Protocols = BuiltInProtocols>
325 void Deserialize(T& var) const
326 {
327 typename aliased_type<T>::type value;
328 _skip = false;
329 _input.Read(value);
330 set_aliased_value(var, value);
331 }
332
333protected:
334 using value_common<T, Reader>::_skip;
335 using value_common<T, Reader>::_input;
336};
337
338
339// Specialization of value for Bond structs with compile-time schema
340template <typename T, typename Reader>
341class value<T, Reader, typename boost::enable_if<is_bond_type<T> >::type>
342 : public value_common<T, Reader>
343{
344public:
345 value(Reader input, bool skip = true)
346 : value_common<T, Reader>(input, skip)
347 {}
348
349 value(value&& rhs) BOND_NOEXCEPT_IF((
350 std::is_nothrow_move_constructible<value_common<T, Reader> >::value))
351 : value_common<T, Reader>(std::move(rhs))
352 {}
353
354 value(const value& that) = default;
355 value& operator=(const value& that) = default;
356
357 // deserialize Bond struct into matching variable
358 template <typename Protocols = BuiltInProtocols, typename X>
359 typename boost::enable_if<is_bond_type<X> >::type
360 Deserialize(X& var) const
361 {
362 _skip = false;
363 bonded<T, Reader>(_input).template Deserialize<Protocols>(var);
364 }
365
366
367 template <typename Protocols = BuiltInProtocols, typename Transform>
368 void _Apply(const Transform& transform) const
369 {
370 _skip = false;
371 Apply<Protocols>(transform, bonded<T, Reader>(_input));
372 }
373
374
375protected:
376 using value_common<T, Reader>::_skip;
377 using value_common<T, Reader>::_input;
378};
379
380
381// Specialization of value for 2-tuples with compile-time schema
382template <typename T1, typename T2, typename Reader>
383class value<std::pair<T1, T2>, Reader>
384{
385public:
386 value(Reader /*input*/, bool skip = true)
387 {
388 BOOST_VERIFY(!skip);
389 }
390};
391
392
393template <typename Protocols, typename X, typename T1, typename T2, typename Reader>
394inline void DeserializeContainer(X& var, const value<std::pair<T1, T2>, Reader&>&, Reader& input);
395
396template <typename Protocols, typename X, typename T, typename Reader>
397typename boost::disable_if<is_container<X> >::type
398inline DeserializeContainer(X& var, const T& element, Reader& input);
399
400template <typename Protocols, typename X, typename T, typename Reader>
401typename boost::enable_if<is_nested_container<X> >::type
402inline DeserializeContainer(X& var, const T& element, Reader& input);
403
404template <typename Protocols, typename X, typename T, typename Reader>
405typename boost::enable_if<is_basic_container<X> >::type
406inline DeserializeContainer(X& var, const T& element, Reader& input);
407
408template <typename Protocols, typename Transform, typename T>
409void DeserializeContainer(const Transform& transform, const value<T, SchemaReader&>& element, SchemaReader&)
410{
411 transform.Container(element, 0);
412}
413
414template <typename Protocols, typename Transform, typename T1, typename T2>
415void DeserializeContainer(const Transform& transform, const value<std::pair<T1, T2>, SchemaReader&>&, SchemaReader& input)
416{
417 transform.Container(value<T1, SchemaReader&>{ input, false }, value<T2, SchemaReader&>{ input, false }, 0);
418}
419
420template <typename Protocols, typename Transform>
421void DeserializeContainer(const Transform& transform, const value<void, SchemaReader&>& element, SchemaReader& input);
422
423
424// Specialization of value for containers with compile-time schema
425template <typename T, typename Reader>
426class value<T, Reader, typename boost::enable_if<is_container<T> >::type>
427 : public value_common<T, Reader>
428{
429public:
430 value(Reader input, bool skip = true)
431 : value_common<T, Reader>(input, skip)
432 {}
433
434 value(value&& rhs) BOND_NOEXCEPT_IF((
435 std::is_nothrow_move_constructible<value_common<T, Reader> >::value))
436 : value_common<T, Reader>(std::move(rhs))
437 {}
438
439 value(const value& that) = default;
440 value& operator=(const value& that) = default;
441
442 // Deserialize container
443 template <typename Protocols = BuiltInProtocols, typename X>
444 typename boost::enable_if_c<is_matching_container<T, X>::value>::type
445 Deserialize(X& var) const
446 {
447 _skip = false;
448 DeserializeContainer<Protocols>(var, value<typename element_type<T>::type, Reader>(_input, false), _input);
449 }
450
451
452 template <typename Protocols = BuiltInProtocols, typename Transform>
453 void _Apply(const Transform& transform) const
454 {
455 _skip = false;
456 DeserializeContainer<Protocols>(transform, value<typename element_type<T>::type, Reader>(_input, false), _input);
457 }
458
459 using value_common<T, Reader>::Deserialize;
460
461
462protected:
463 using value_common<T, Reader>::_input;
464 using value_common<T, Reader>::_skip;
465};
466
467
468template <typename Protocols, typename X, typename T, typename Reader>
469typename boost::disable_if<is_container<X> >::type
470inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input);
471
472template <typename Protocols, typename X, typename T, typename Reader>
473typename boost::enable_if<is_nested_container<X> >::type
474inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input);
475
476template <typename Protocols, typename X, typename T, typename Reader>
477typename boost::enable_if<is_basic_container<X> >::type
478inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input);
479
480template <typename Protocols, typename Transform>
481void DeserializeMap(const Transform& transform, BondDataType keyType, const value<void, SchemaReader&>& element, SchemaReader& input);
482
483
484// Specialization of value for data described by runtime schema
485template <typename Reader>
486class value<void, Reader>
487 : detail::nonassignable
488{
489public:
490 value(Reader input, const RuntimeSchema& schema, bool skip = true)
491 : _input(input),
492 _schema(schema),
493 _skip(skip)
494 {}
495
496 value(Reader input, BondDataType type, bool skip = true)
497 : _input(input),
498 _schema(_schemaDef),
499 _skip(skip)
500 {
501 _schemaDef.root.id = type;
502 }
503
504 value(value&& rhs) BOND_NOEXCEPT_IF(
505 BOND_NOEXCEPT_EXPR(detail::move_data<Reader>(rhs._input))
506 && std::is_nothrow_move_constructible<SchemaDef>::value
507 && std::is_nothrow_move_constructible<RuntimeSchema>::value)
508 : _input(detail::move_data<Reader>(rhs._input)),
509 _schemaDef(std::move(rhs._schemaDef)),
510 _schema(std::move(rhs._schema)),
511 _skip(std::move(rhs._skip))
512 {
513 rhs._skip = false;
514 }
515
516 value(const value& that) = default;
517 value& operator=(const value& that) = default;
518
519 ~value()
520 {
521 // skip the value if it has not been read
522 if (_skip)
523 bond::Skip(_input, _schema, std::nothrow);
524 }
525
526 void Skip() const
527 {
528 _skip = false;
529 bond::Skip(_input, _schema);
530 }
531
532
533 // Deserialize container
534 template <typename Protocols = BuiltInProtocols, typename X>
535 typename boost::enable_if_c<is_container<X>::value && !is_map_container<X>::value>::type
536 Deserialize(X& var) const
537 {
538 if (_schema.GetTypeId() == get_type_id<X>::value)
539 {
540 _skip = false;
541 DeserializeContainer<Protocols>(var,
542 value<void, Reader>(_input, element_schema(_schema), false), _input);
543 }
544 else
545 {
546 Skip();
547 }
548 }
549
550
551 // Deserialize map
552 template <typename Protocols = BuiltInProtocols, typename X>
553 typename boost::enable_if<is_map_container<X> >::type
554 Deserialize(X& var) const
555 {
556 if (_schema.GetTypeId() == get_type_id<X>::value)
557 {
558 _skip = false;
559 DeserializeMap<Protocols>(var, key_schema(_schema).GetTypeId(),
560 value<void, Reader>(_input, element_schema(_schema), false), _input);
561 }
562 else
563 {
564 Skip();
565 }
566 }
567
568
569 // Deserialize Bond struct
570 template <typename Protocols = BuiltInProtocols, typename X>
571 typename boost::enable_if<is_bond_type<X> >::type
572 Deserialize(X& var) const
573 {
574 if (_schema.GetTypeId() == get_type_id<X>::value)
575 {
576 _skip = false;
577 bonded<void, Reader>(_input, _schema).template Deserialize<Protocols>(var);
578 }
579 else
580 {
581 Skip();
582 }
583 }
584
585
586 template <typename Protocols = BuiltInProtocols, typename Transform>
587 void _Apply(const Transform& transform) const
588 {
589 _skip = false;
590
591 if (_schema.GetTypeId() == bond::BT_STRUCT)
592 {
593 Apply<Protocols>(transform, bonded<void, Reader>(_input, _schema));
594 }
595 else if(_schema.GetTypeId() == bond::BT_MAP)
596 {
597 DeserializeMap<Protocols>(transform, key_schema(_schema).GetTypeId(),
598 value<void, Reader>(_input, element_schema(_schema), false), _input);
599 }
600 else
601 {
602 BOOST_ASSERT(_schema.GetTypeId() == bond::BT_LIST || _schema.GetTypeId() == bond::BT_SET);
603
604 DeserializeContainer<Protocols>(transform,
605 value<void, Reader>(_input, element_schema(_schema), false), _input);
606 }
607 }
608
609
610 // skip value of non-matching type
611 template <typename Protocols = BuiltInProtocols, typename X>
612 typename boost::disable_if_c<is_container<X>::value || is_bond_type<X>::value>::type
613 Deserialize(X& /*var*/) const
614 {
615 Skip();
616 }
617
618
619 BondDataType GetTypeId() const
620 {
621 return _schema.GetTypeId();
622 }
623
624
625 RuntimeSchema GetRuntimeSchema() const
626 {
627 return _schema;
628 }
629
630private:
631 Reader _input;
632 SchemaDef _schemaDef;
633 RuntimeSchema _schema;
634 mutable bool _skip;
635};
636
637
638template <typename Protocols, typename Transform>
639void DeserializeContainer(const Transform& transform, const value<void, SchemaReader&>& element, SchemaReader& input)
640{
641 switch (element.GetTypeId())
642 {
643 case bond::BT_SET:
644 case bond::BT_MAP:
645 case bond::BT_LIST:
646 case bond::BT_STRUCT:
647 transform.Container(element, 0);
648 break;
649 default:
650 detail::BasicTypeContainer<Protocols>(transform, element.GetTypeId(), input, 0);
651 break;
652 }
653}
654
655
656template <typename Protocols, typename X, typename I, typename T>
657typename boost::enable_if<require_modify_element<X> >::type
658inline DeserializeElement(X& var, const I& item, const T& element)
659{
660 struct DeserializeImpl
661 {
662 DeserializeImpl(const T& element)
663 : element(element)
664 {}
665
666 void operator()(typename element_type<X>::type& e)
667 {
668 this->element.template Deserialize<Protocols>(e);
669 }
670
671 const T& element;
672 };
673
674 modify_element(var, item, DeserializeImpl(element));
675}
676
677template <typename Protocols, typename X, typename I, typename T>
678typename boost::disable_if<require_modify_element<X> >::type
679inline DeserializeElement(X&, I& item, const T& element)
680{
681 element.template Deserialize<Protocols>(item);
682}
683
684
685template <typename Protocols, typename X, typename T>
686typename boost::enable_if_c<detail::is_deserialize_direct<X, T>::value>::type
687inline DeserializeElements(X& var, const T& element, uint32_t size)
688{
689 // In lists of basic types we can easily verify buffer size (and we have done so
690 // by the time execution gets here), so it is safe to allocate the entire array.
691 resize_list(var, size);
692
693 for (enumerator<X> items(var); items.more();)
694 DeserializeElement<Protocols>(var, items.next(), element);
695}
696
697
698template <typename Protocols, typename X, typename T>
699typename boost::enable_if_c<is_matching<T, X>::value>::type
700inline DeserializeElements(nullable<X>& var, const T& element, uint32_t size)
701{
702 // No need to guard against memory allocation attack here. Since X is nullable,
703 // at most 1 element will be allocated.
704 resize_list(var, size);
705
706 for (enumerator<nullable<X> > items(var); items.more(); --size)
707 element.template Deserialize<Protocols>(items.next());
708
709 // Wire representation and interface for nullable is the same as for list.
710 // However nullable can "contain" at most one element. If there are more
711 // elements in the payload we skip them.
712 detail::SkipElements(element, size);
713}
714
715template<typename T>
716inline T& get_ref(T& t) noexcept
717{
718 return t;
719}
720
721template <typename Protocols, typename X, typename T>
722typename boost::enable_if_c<detail::is_deserialize_incremental<X, T>::value>::type
723inline DeserializeElements(X& var, const T& element, uint32_t size)
724{
725 reset_list(var, size);
726
727 // Containers of structs cannot be easily checked. We resort to incrementally
728 // growing the array.
729 while (size--)
730 {
731 auto e(make_element(var));
732 DeserializeElement<Protocols>(var, get_ref(e), element);
733 insert_list(var, e);
734 }
735}
736
737
738template <typename Protocols, typename Reader>
739inline void DeserializeElements(blob& var, const value<blob::value_type, Reader&>& element, uint32_t size)
740{
741 element.template Deserialize<Protocols>(var, size);
742}
743
744
745template <typename Protocols, typename X, typename T>
746typename boost::enable_if_c<is_set_container<X>::value
747 && is_element_matching<T, X>::value>::type
748inline DeserializeElements(X& var, const T& element, uint32_t size)
749{
750 clear_set(var);
751
752 typename element_type<X>::type e(make_element(var));
753
754 while (size--)
755 {
756 element.template Deserialize<Protocols>(e);
757 set_insert(var, e);
758 }
759}
760
761
762template <typename Protocols, typename X, typename T>
763typename boost::enable_if_c<!is_element_matching<T, X>::value >::type
764inline DeserializeElements(X&, const T& element, uint32_t size)
765{
766 detail::SkipElements(element, size);
767}
768
769
770template <typename Protocols, typename Transform, typename T>
771inline void DeserializeElements(const Transform& transform, const T& element, uint32_t size)
772{
773 transform.Container(element, size);
774}
775
776
777template <typename T1, typename T2, typename Reader>
778inline void SkipContainer(const value<std::pair<T1, T2>, Reader&>&, Reader& input)
779{
780 BOOST_STATIC_ASSERT(uses_static_parser<Reader>::value);
781
782 SkipMap(get_type_id<T1>::value, value<T2, Reader&>(input, false), input);
783}
784
785
786template <typename T, typename Reader>
787inline void SkipContainer(const T& element, Reader& input)
788{
789 BOOST_STATIC_ASSERT(uses_static_parser<Reader>::value);
790
791 bond::detail::RecursionGuard guard;
792
793 uint32_t size;
794
795 {
796 BondDataType type;
797 input.ReadContainerBegin(size, type);
798 }
799
800 detail::SkipElements(element, size);
801
802 input.ReadContainerEnd();
803}
804
805
806template <typename Protocols, typename X, typename T1, typename T2, typename Reader>
807inline void DeserializeContainer(X& var, const value<std::pair<T1, T2>, Reader&>&, Reader& input)
808{
809 return DeserializeMap<Protocols>(var, get_type_id<T1>::value, value<T2, Reader&>(input, false), input);
810}
811
812
813template <typename Protocols, typename X, typename T, typename Reader>
814typename boost::disable_if<is_container<X> >::type
815inline DeserializeContainer(X& var, const T& element, Reader& input)
816{
817 BondDataType type = GetTypeId(element);
818 uint32_t size = 0;
819
820 bond::detail::RecursionGuard guard;
821
822 input.ReadContainerBegin(size, type);
823
824 switch (type)
825 {
826 case bond::BT_SET:
827 case bond::BT_MAP:
828 case bond::BT_LIST:
829 case bond::BT_STRUCT:
830 {
831 // Buffer check is not needed here since we do not preallocate here. Elements are deserialized
832 // into a growing array unless the array is of a basic type.
833 if (type == GetTypeId(element))
834 {
835 DeserializeElements<Protocols>(var, element, size);
836 }
837 else
838 {
839 DeserializeElements<Protocols>(var, value<void, Reader&>(input, type, false), size);
840 }
841 break;
842 }
843 default:
844 {
845 // Buffer checks are performed inside as needed.
846 detail::BasicTypeContainer<Protocols>(var, type, input, size);
847 break;
848 }
849 }
850
851 input.ReadContainerEnd();
852}
853
854
855template <typename Protocols, typename X, typename T, typename Reader>
856typename boost::enable_if<is_nested_container<X> >::type
857inline DeserializeContainer(X& var, const T& element, Reader& input)
858{
859 BondDataType type = GetTypeId(element);
860 uint32_t size;
861
862 bond::detail::RecursionGuard guard;
863
864 input.ReadContainerBegin(size, type);
865
866 if (type == GetTypeId(element))
867 {
868 // Buffer check is not needed here. We use a growing array for lists of nonbasic types.
869 DeserializeElements<Protocols>(var, element, size);
870 }
871 else
872 {
873 detail::SkipElements(type, input, size);
874 }
875
876 input.ReadContainerEnd();
877}
878
879
880template <typename Protocols, typename X, typename T, typename Reader>
881typename boost::enable_if<is_basic_container<X> >::type
882inline DeserializeContainer(X& var, const T& element, Reader& input)
883{
884 BondDataType type = GetTypeId(element);
885 uint32_t size;
886
887 bond::detail::RecursionGuard guard;
888
889 input.ReadContainerBegin(size, type);
890
891 switch (type)
892 {
893 case bond::BT_SET:
894 case bond::BT_MAP:
895 case bond::BT_LIST:
896 case bond::BT_STRUCT:
897 {
898 if (type == GetTypeId(element))
899 {
900 detail::SkipElements(element, size);
901 }
902 else
903 {
904 while (size--)
905 Skip(input, type);
906 }
907 break;
908 }
909 default:
910 {
911 // Buffer checks performed inside as needed.
912 detail::MatchingTypeContainer<Protocols>(var, type, input, size);
913 break;
914 }
915 }
916
917 input.ReadContainerEnd();
918}
919
920
921template <typename Protocols, typename Transform>
922void DeserializeMap(const Transform& transform, BondDataType keyType, const value<void, SchemaReader&>& element, SchemaReader& input)
923{
924 bond::detail::RecursionGuard guard;
925
926 switch (element.GetTypeId())
927 {
928 case bond::BT_SET:
929 case bond::BT_MAP:
930 case bond::BT_LIST:
931 case bond::BT_STRUCT:
932 detail::MapByKey<Protocols>(transform, keyType, element, input, 0);
933 break;
934 default:
935 detail::MapByElement<Protocols>(transform, keyType, element.GetTypeId(), input, 0);
936 break;
937 }
938}
939
940
941template <typename Protocols, typename X, typename Key, typename T>
942typename boost::enable_if<is_map_key_matching<Key, X> >::type
943inline DeserializeMapElements(X& var, const Key& key, const T& element, uint32_t size)
944{
945 BOOST_STATIC_ASSERT((is_map_element_matching<T, X>::value));
946
947 clear_map(var);
948
949 typename element_type<X>::type::first_type k(make_key(var));
950
951 while (size--)
952 {
953 key.template Deserialize<Protocols>(k);
954
955#ifndef NDEBUG
956 // In debug build To<T> asserts that optional fields are set to default
957 // values before deserialization; if invalid map payload contains duplicate
958 // keys the second time we deserialize a value it will trigger the assert.
959 element.template Deserialize<Protocols>(mapped_at(var, k) = make_value(var));
960#else
961 element.template Deserialize<Protocols>(mapped_at(var, k));
962#endif
963 }
964}
965
966
967template <typename Protocols, typename X, typename Key, typename T>
968typename boost::disable_if<is_map_key_matching<Key, X> >::type
969inline DeserializeMapElements(X&, const Key& key, const T& element, uint32_t size)
970{
971 while (size--)
972 {
973 key.Skip();
974 element.Skip();
975 }
976}
977
978
979template <typename Protocols, typename Transform, typename Key, typename T>
980inline void DeserializeMapElements(const Transform& transform, const Key& key, const T& element, uint32_t size)
981{
982 transform.Container(key, element, size);
983}
984
985
986template <typename T, typename Reader>
987inline void SkipMap(BondDataType keyType, const T& element, Reader& input)
988{
989 BOOST_STATIC_ASSERT(uses_static_parser<Reader>::value);
990
991 bond::detail::RecursionGuard guard;
992
993 uint32_t size;
994
995 {
996 std::pair<BondDataType, BondDataType> type;
997
998 input.ReadContainerBegin(size, type);
999 }
1000
1001 detail::SkipElements(keyType, element, input, size);
1002
1003 input.ReadContainerEnd();
1004}
1005
1006
1007template <typename Protocols, typename X, typename T, typename Reader>
1008typename boost::disable_if<is_container<X> >::type
1009inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input)
1010{
1011 bond::detail::RecursionGuard guard;
1012
1013 std::pair<BondDataType, BondDataType> type(keyType, GetTypeId(element));
1014 uint32_t size = 0;
1015
1016 input.ReadContainerBegin(size, type);
1017
1018 switch (type.second)
1019 {
1020 case bond::BT_SET:
1021 case bond::BT_MAP:
1022 case bond::BT_LIST:
1023 case bond::BT_STRUCT:
1024 {
1025 if (type.second == GetTypeId(element))
1026 {
1027 detail::MapByKey<Protocols>(var, type.first, element, input, size);
1028 }
1029 else
1030 {
1031 detail::MapByKey<Protocols>(var, type.first, value<void, Reader&>(input, type.second, false), input, size);
1032 }
1033 break;
1034 }
1035 default:
1036 {
1037 detail::MapByElement<Protocols>(var, type.first, type.second, input, size);
1038 break;
1039 }
1040 }
1041
1042 input.ReadContainerEnd();
1043}
1044
1045
1046template <typename Protocols, typename X, typename T, typename Reader>
1047typename boost::enable_if<is_nested_container<X> >::type
1048inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input)
1049{
1050 bond::detail::RecursionGuard guard;
1051
1052 std::pair<BondDataType, BondDataType> type(keyType, GetTypeId(element));
1053 uint32_t size;
1054
1055 input.ReadContainerBegin(size, type);
1056
1057 if (type.second == GetTypeId(element))
1058 {
1059 detail::MapByKey<Protocols>(var, type.first, element, input, size);
1060 }
1061 else
1062 {
1063 detail::SkipElements(type.first, type.second, input, size);
1064 }
1065
1066 input.ReadContainerEnd();
1067}
1068
1069
1070template <typename Protocols, typename X, typename T, typename Reader>
1071typename boost::enable_if<is_basic_container<X> >::type
1072inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input)
1073{
1074 bond::detail::RecursionGuard guard;
1075
1076 std::pair<BondDataType, BondDataType> type(keyType, GetTypeId(element));
1077 uint32_t size;
1078
1079 input.ReadContainerBegin(size, type);
1080
1081 switch (type.second)
1082 {
1083 case bond::BT_SET:
1084 case bond::BT_MAP:
1085 case bond::BT_LIST:
1086 case bond::BT_STRUCT:
1087 {
1088 if (type.second == GetTypeId(element))
1089 {
1090 detail::SkipElements(type.first, element, input, size);
1091 }
1092 else
1093 {
1094 while (size--)
1095 {
1096 input.Skip(type.first);
1097 Skip(input, type.second);
1098 }
1099 }
1100 break;
1101 }
1102 default:
1103 {
1104 detail::MatchingMapByElement<Protocols>(var, type.first, type.second, input, size);
1105 break;
1106 }
1107 }
1108
1109 input.ReadContainerEnd();
1110}
1111
1112} // namespace bond
1113
1114
1115#ifdef BOND_LIB_TYPE
1116#if BOND_LIB_TYPE != BOND_LIB_TYPE_HEADER
1117#include "detail/value_extern.h"
1118#endif
1119#else
1120#error BOND_LIB_TYPE is undefined
1121#endif
Represents runtime schema See User's Manual
Definition runtime_schema.h:26
Memory blob.
Definition blob.h:24
Represents data for a struct T known at compile-time.
Definition bonded.h:63
void Skip()
Skip struct data in the underlying payload.
Definition bonded.h:214
namespace bond
Definition apply.h:17
RuntimeSchema GetRuntimeSchema()
Returns an instance of RuntimeSchema for a user defined struct.
Definition schema.h:336
void Deserialize(Reader input, T &obj)
Deserialize an object from a protocol reader.
Definition bond.h:28