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
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
677
678template <typename Protocols, typename X, typename I, typename T>
679typename boost::disable_if<require_modify_element<X> >::type
680inline DeserializeElement(X&, I& item, const T& element)
681{
682 element.template Deserialize<Protocols>(item);
683}
684
685
686// Read elements of a list
687template <typename Protocols, typename X, typename T>
688typename boost::enable_if_c<is_list_container<X>::value
689 && is_element_matching<T, X>::value>::type
690inline DeserializeElements(X& var, const T& element, uint32_t size)
691{
692 resize_list(var, size);
693
694 for (enumerator<X> items(var); items.more();)
695 DeserializeElement<Protocols>(var, items.next(), element);
696}
697
698
699template <typename Protocols, typename X, typename T>
700typename boost::enable_if<is_matching<T, X> >::type
701inline DeserializeElements(nullable<X>& var, const T& element, uint32_t size)
702{
703 resize_list(var, size);
704
705 for (enumerator<nullable<X> > items(var); items.more(); --size)
706 element.template Deserialize<Protocols>(items.next());
707
708 // Wire representation and interface for nullable is the same as for list.
709 // However nullable can "contain" at most one element. If there are more
710 // elements in the payload we skip them.
711 detail::SkipElements(element, size);
712}
713
714
715template <typename Protocols, typename Reader>
716inline void DeserializeElements(blob& var, const value<blob::value_type, Reader&>& element, uint32_t size)
717{
718 element.template Deserialize<Protocols>(var, size);
719}
720
721
722template <typename Protocols, typename X, typename T>
723typename boost::enable_if_c<is_set_container<X>::value
724 && is_element_matching<T, X>::value>::type
725inline DeserializeElements(X& var, const T& element, uint32_t size)
726{
727 clear_set(var);
728
729 typename element_type<X>::type e(make_element(var));
730
731 while (size--)
732 {
733 element.template Deserialize<Protocols>(e);
734 set_insert(var, e);
735 }
736}
737
738
739template <typename Protocols, typename X, typename T>
740typename boost::disable_if<is_element_matching<T, X> >::type
741inline DeserializeElements(X&, const T& element, uint32_t size)
742{
743 detail::SkipElements(element, size);
744}
745
746
747template <typename Protocols, typename Transform, typename T>
748inline void DeserializeElements(const Transform& transform, const T& element, uint32_t size)
749{
750 transform.Container(element, size);
751}
752
753
754template <typename T1, typename T2, typename Reader>
755inline void SkipContainer(const value<std::pair<T1, T2>, Reader&>&, Reader& input)
756{
757 BOOST_STATIC_ASSERT(uses_static_parser<Reader>::value);
758
759 SkipMap(get_type_id<T1>::value, value<T2, Reader&>(input, false), input);
760}
761
762
763template <typename T, typename Reader>
764inline void SkipContainer(const T& element, Reader& input)
765{
766 BOOST_STATIC_ASSERT(uses_static_parser<Reader>::value);
767
768 uint32_t size;
769
770 {
771 BondDataType type;
772 input.ReadContainerBegin(size, type);
773 }
774
775 detail::SkipElements(element, size);
776
777 input.ReadContainerEnd();
778}
779
780
781template <typename Protocols, typename X, typename T1, typename T2, typename Reader>
782inline void DeserializeContainer(X& var, const value<std::pair<T1, T2>, Reader&>&, Reader& input)
783{
784 return DeserializeMap<Protocols>(var, get_type_id<T1>::value, value<T2, Reader&>(input, false), input);
785}
786
787
788template <typename Protocols, typename X, typename T, typename Reader>
789typename boost::disable_if<is_container<X> >::type
790inline DeserializeContainer(X& var, const T& element, Reader& input)
791{
792 BondDataType type = GetTypeId(element);
793 uint32_t size = 0;
794
795 input.ReadContainerBegin(size, type);
796
797 switch (type)
798 {
799 case bond::BT_SET:
800 case bond::BT_MAP:
801 case bond::BT_LIST:
802 case bond::BT_STRUCT:
803 {
804 if (type == GetTypeId(element))
805 {
806 DeserializeElements<Protocols>(var, element, size);
807 }
808 else
809 {
810 DeserializeElements<Protocols>(var, value<void, Reader&>(input, type, false), size);
811 }
812 break;
813 }
814 default:
815 {
816 detail::BasicTypeContainer<Protocols>(var, type, input, size);
817 break;
818 }
819 }
820
821 input.ReadContainerEnd();
822}
823
824
825template <typename Protocols, typename X, typename T, typename Reader>
826typename boost::enable_if<is_nested_container<X> >::type
827inline DeserializeContainer(X& var, const T& element, Reader& input)
828{
829 BondDataType type = GetTypeId(element);
830 uint32_t size;
831
832 input.ReadContainerBegin(size, type);
833
834 if (type == GetTypeId(element))
835 {
836 DeserializeElements<Protocols>(var, element, size);
837 }
838 else
839 {
840 detail::SkipElements(type, input, size);
841 }
842
843 input.ReadContainerEnd();
844}
845
846
847template <typename Protocols, typename X, typename T, typename Reader>
848typename boost::enable_if<is_basic_container<X> >::type
849inline DeserializeContainer(X& var, const T& element, Reader& input)
850{
851 BondDataType type = GetTypeId(element);
852 uint32_t size;
853
854 input.ReadContainerBegin(size, type);
855
856 switch (type)
857 {
858 case bond::BT_SET:
859 case bond::BT_MAP:
860 case bond::BT_LIST:
861 case bond::BT_STRUCT:
862 {
863 if (type == GetTypeId(element))
864 {
865 detail::SkipElements(element, size);
866 }
867 else
868 {
869 while (size--)
870 Skip(input, type);
871 }
872 break;
873 }
874 default:
875 {
876 detail::MatchingTypeContainer<Protocols>(var, type, input, size);
877 break;
878 }
879 }
880
881 input.ReadContainerEnd();
882}
883
884
885template <typename Protocols, typename Transform>
886void DeserializeMap(const Transform& transform, BondDataType keyType, const value<void, SchemaReader&>& element, SchemaReader& input)
887{
888 switch (element.GetTypeId())
889 {
890 case bond::BT_SET:
891 case bond::BT_MAP:
892 case bond::BT_LIST:
893 case bond::BT_STRUCT:
894 detail::MapByKey<Protocols>(transform, keyType, element, input, 0);
895 break;
896 default:
897 detail::MapByElement<Protocols>(transform, keyType, element.GetTypeId(), input, 0);
898 break;
899 }
900}
901
902
903template <typename Protocols, typename X, typename Key, typename T>
904typename boost::enable_if<is_map_key_matching<Key, X> >::type
905inline DeserializeMapElements(X& var, const Key& key, const T& element, uint32_t size)
906{
907 BOOST_STATIC_ASSERT((is_map_element_matching<T, X>::value));
908
909 clear_map(var);
910
911 typename element_type<X>::type::first_type k(make_key(var));
912
913 while (size--)
914 {
915 key.template Deserialize<Protocols>(k);
916
917#ifndef NDEBUG
918 // In debug build To<T> asserts that optional fields are set to default
919 // values before deserialization; if invalid map payload contains duplicate
920 // keys the second time we deserialize a value it will trigger the assert.
921 element.template Deserialize<Protocols>(mapped_at(var, k) = make_value(var));
922#else
923 element.template Deserialize<Protocols>(mapped_at(var, k));
924#endif
925 }
926}
927
928
929template <typename Protocols, typename X, typename Key, typename T>
930typename boost::disable_if<is_map_key_matching<Key, X> >::type
931inline DeserializeMapElements(X&, const Key& key, const T& element, uint32_t size)
932{
933 while (size--)
934 {
935 key.Skip();
936 element.Skip();
937 }
938}
939
940
941template <typename Protocols, typename Transform, typename Key, typename T>
942inline void DeserializeMapElements(const Transform& transform, const Key& key, const T& element, uint32_t size)
943{
944 transform.Container(key, element, size);
945}
946
947
948template <typename T, typename Reader>
949inline void SkipMap(BondDataType keyType, const T& element, Reader& input)
950{
951 BOOST_STATIC_ASSERT(uses_static_parser<Reader>::value);
952
953 uint32_t size;
954
955 {
956 std::pair<BondDataType, BondDataType> type;
957
958 input.ReadContainerBegin(size, type);
959 }
960
961 detail::SkipElements(keyType, element, input, size);
962
963 input.ReadContainerEnd();
964}
965
966
967template <typename Protocols, typename X, typename T, typename Reader>
968typename boost::disable_if<is_container<X> >::type
969inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input)
970{
971 std::pair<BondDataType, BondDataType> type(keyType, GetTypeId(element));
972 uint32_t size = 0;
973
974 input.ReadContainerBegin(size, type);
975
976 switch (type.second)
977 {
978 case bond::BT_SET:
979 case bond::BT_MAP:
980 case bond::BT_LIST:
981 case bond::BT_STRUCT:
982 {
983 if (type.second == GetTypeId(element))
984 {
985 detail::MapByKey<Protocols>(var, type.first, element, input, size);
986 }
987 else
988 {
989 detail::MapByKey<Protocols>(var, type.first, value<void, Reader&>(input, type.second, false), input, size);
990 }
991 break;
992 }
993 default:
994 {
995 detail::MapByElement<Protocols>(var, type.first, type.second, input, size);
996 break;
997 }
998 }
999
1000 input.ReadContainerEnd();
1001}
1002
1003
1004template <typename Protocols, typename X, typename T, typename Reader>
1005typename boost::enable_if<is_nested_container<X> >::type
1006inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input)
1007{
1008 std::pair<BondDataType, BondDataType> type(keyType, GetTypeId(element));
1009 uint32_t size;
1010
1011 input.ReadContainerBegin(size, type);
1012
1013 if (type.second == GetTypeId(element))
1014 {
1015 detail::MapByKey<Protocols>(var, type.first, element, input, size);
1016 }
1017 else
1018 {
1019 detail::SkipElements(type.first, type.second, input, size);
1020 }
1021
1022 input.ReadContainerEnd();
1023}
1024
1025
1026template <typename Protocols, typename X, typename T, typename Reader>
1027typename boost::enable_if<is_basic_container<X> >::type
1028inline DeserializeMap(X& var, BondDataType keyType, const T& element, Reader& input)
1029{
1030 std::pair<BondDataType, BondDataType> type(keyType, GetTypeId(element));
1031 uint32_t size;
1032
1033 input.ReadContainerBegin(size, type);
1034
1035 switch (type.second)
1036 {
1037 case bond::BT_SET:
1038 case bond::BT_MAP:
1039 case bond::BT_LIST:
1040 case bond::BT_STRUCT:
1041 {
1042 if (type.second == GetTypeId(element))
1043 {
1044 detail::SkipElements(type.first, element, input, size);
1045 }
1046 else
1047 {
1048 while (size--)
1049 {
1050 input.Skip(type.first);
1051 Skip(input, type.second);
1052 }
1053 }
1054 break;
1055 }
1056 default:
1057 {
1058 detail::MatchingMapByElement<Protocols>(var, type.first, type.second, input, size);
1059 break;
1060 }
1061 }
1062
1063 input.ReadContainerEnd();
1064}
1065
1066
1067} // namespace bond
1068
1069
1070#ifdef BOND_LIB_TYPE
1071#if BOND_LIB_TYPE != BOND_LIB_TYPE_HEADER
1072#include "detail/value_extern.h"
1073#endif
1074#else
1075#error BOND_LIB_TYPE is undefined
1076#endif
Memory blob.
Definition: blob.h:24
namespace bond
Definition: apply.h:17
RuntimeSchema GetRuntimeSchema()
Returns an instance of RuntimeSchema for a user defined struct.
Definition: schema.h:330
void Deserialize(Reader input, T &obj)
Deserialize an object from a protocol reader.
Definition: bond.h:27
STL namespace.