Bond
 
Loading...
Searching...
No Matches
reflection.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 "bond_fwd.h"
9#include "detail/metadata.h"
10
11#include <bond/core/bond_types.h>
12
13#include <boost/mpl/copy_if.hpp>
14#include <boost/mpl/find_if.hpp>
15#include <boost/mpl/for_each.hpp>
16#include <boost/mpl/list.hpp>
17#include <boost/mpl/push_front.hpp>
18#include <boost/mpl/transform.hpp>
19#include <boost/static_assert.hpp>
20
21#include <functional>
22
23namespace bond
24{
25
26using boost::mpl::_;
27
28template <typename T> struct
29remove_maybe
30{
31 typedef T type;
32};
33
34
35template <typename T> struct
36remove_maybe<maybe<T> >
37{
38 typedef typename remove_maybe<T>::type type;
39};
40
41
42BOND_STATIC_CONSTEXPR uint16_t invalid_field_id = 0xffff;
43
44
46namespace reflection
47{
48//
49// Helper classes/templates
50//
51typedef std::map<std::string, std::string> Attributes;
52
53
54// field is required
55using required_field_modifier = std::integral_constant<bond::Modifier, bond::Required>;
56
57// field is optional
58using optional_field_modifier = std::integral_constant<bond::Modifier, bond::Optional>;
59
60// field is required optional
61using required_optional_field_modifier = std::integral_constant<bond::Modifier, bond::RequiredOptional>;
62
63
65template <
66 uint16_t field_id,
67 typename ModifierTag,
68 typename Struct,
69 typename FieldType,
70 FieldType Struct::*field_ptr,
71 const bond::Metadata* metadata_ptr>
73{
74 // Note: When introducing new names inside this scope, remember to update the
75 // fieldTemplateReservedNames list in Reflection_h.hs
76
78 typedef Struct struct_type;
79
81 typedef FieldType Struct::*field_pointer;
82
84 typedef typename remove_maybe<FieldType>::type field_type;
85
87 typedef FieldType value_type;
88
95 typedef ModifierTag field_modifier;
96
98 static const Metadata& metadata;
99
101 static const field_pointer field;
102
104 BOND_STATIC_CONSTEXPR uint16_t id = field_id;
105
107 static
108 const value_type& GetVariable(const struct_type& object)
109 {
110 return object.*field_ptr;
111 }
112
114 static
116 {
117 return object.*field_ptr;
118 }
119
120 BOOST_STATIC_ASSERT(field_id != invalid_field_id);
121};
122
123
124template <
125 uint16_t field_id,
126 typename ModifierTag,
127 typename Struct,
128 typename FieldType,
129 FieldType Struct::*field_ptr,
130 const Metadata* metadata_ptr>
131const bond::Metadata&
133
134template
135<
136 uint16_t field_id,
137 typename ModifierTag,
138 typename Struct,
139 typename FieldType,
140 FieldType Struct::*field_ptr,
141 const Metadata* metadata_ptr
142>
145
146
147// Metadata initializer for fields
148inline
149bond::Metadata MetadataInit(const char* name)
150{
151 bond::Metadata metadata;
152
153 metadata.name = name;
154 return metadata;
155}
156
157inline
158bond::Metadata MetadataInit(const char* name, bond::Modifier modifier, const Attributes& attributes)
159{
160 bond::Metadata metadata;
161
162 metadata.name = name;
163 metadata.modifier = modifier;
164 metadata.attributes = attributes;
165
166 return metadata;
167}
168
169inline
170bond::Metadata MetadataInit(const char* name, const Attributes& attributes)
171{
172 bond::Metadata metadata;
173
174 metadata.name = name;
175 metadata.attributes = attributes;
176
177 return metadata;
178}
179
180template <typename T>
181bond::Metadata MetadataInit(const T& default_value, const char* name)
182{
183 bond::Metadata metadata;
184
185 metadata.name = name;
186 detail::VariantSet(metadata.default_value, default_value);
187 return metadata;
188}
189
190template <typename T>
191bond::Metadata MetadataInit(const T& default_value, const char* name, bond::Modifier modifier, const Attributes& attributes)
192{
193 bond::Metadata metadata = MetadataInit(name, modifier, attributes);
194
195 detail::VariantSet(metadata.default_value, default_value);
196
197 return metadata;
198}
199
200struct nothing
201{};
202
203inline
204bond::Metadata MetadataInit(const nothing&, const char* name)
205{
206 bond::Metadata metadata;
207
208 metadata.name = name;
209 metadata.default_value.nothing = true;
210 return metadata;
211}
212
213inline
214bond::Metadata MetadataInit(const nothing&, const char* name, bond::Modifier modifier, const Attributes& attributes)
215{
216 bond::Metadata metadata = MetadataInit(name, modifier, attributes);
217
218 metadata.default_value.nothing = true;
219
220 return metadata;
221}
222
223
224// Metadata initializer for structs
225inline
226bond::Metadata MetadataInit(const char* name, const char* qual_name, const Attributes& attributes)
227{
228 bond::Metadata metadata;
229
230 metadata.name = name;
231 metadata.qualified_name = qual_name;
232 metadata.attributes = attributes;
233
234 return metadata;
235}
236
237
238// Metadata initializer for generic structs
239template <typename Params>
240bond::Metadata MetadataInit(const char* name, const char* qual_name, const Attributes& attributes)
241{
242 bond::Metadata metadata = MetadataInit(name, qual_name, attributes);
243
244 std::string params;
245
246 // boost::mpl::for_each instantiates object of each type in the sequence.
247 // We transform the Params to a sequence of type pointers to avoid creating
248 // actual complex types that might not even support default ctor.
249 typedef typename boost::mpl::transform<Params, std::add_pointer<_> >::type ParamsPtr;
250
251 boost::mpl::for_each<ParamsPtr>(detail::TypeListBuilder(params));
252
253 metadata.name += "<" + params + ">";
254 metadata.qualified_name += "<" + params + ">";
255
256 return metadata;
257}
258
259} // namespace reflection
260
261
262const reflection::nothing nothing = {};
263
264template <typename T, typename Iter> struct
265field_id
266 : std::integral_constant<uint16_t, boost::mpl::deref<Iter>::type::id> {};
267
268template <typename T> struct
269field_id<T, typename boost::mpl::end<T>::type>
270 : std::integral_constant<uint16_t, invalid_field_id> {};
271
272
273template <typename T, uint16_t minId = 0> struct
274next_required_field
275{
276private:
277 template <typename Field> struct
278 is_next_required
279 : std::integral_constant<bool,
280 Field::id >= minId
281 && std::is_same<typename Field::field_modifier, typename reflection::required_field_modifier>::value> {};
282
283public:
284 BOND_STATIC_CONSTEXPR uint16_t value = field_id<T, typename boost::mpl::find_if<T, is_next_required<_> >::type>::value;
285};
286
287
288struct no_base {};
289
290
291template <typename T, typename Enable = void> struct
292is_writer
293 : std::false_type {};
294
295template <typename T> struct
296is_writer<T,
297#ifdef BOND_NO_SFINAE_EXPR
298 typename boost::enable_if<check_method<void (T::*)(const Metadata&, bool), &T::WriteStructBegin> >::type>
299#else
300 detail::mpl::void_t<decltype(std::declval<T>().WriteStructBegin(
301 std::declval<Metadata>(),
302 std::declval<bool>()))>>
303#endif
304 : std::true_type {};
305
306
307template <typename T>
308inline typename T::base*
309base_class()
310{
311 return NULL;
312}
313
314
315template <typename T> struct
316remove_bonded
317{
318 typedef T type;
319};
320
321
322template <typename T, typename Reader> struct
323remove_bonded<bonded<T, Reader> >
324{
325 typedef typename remove_bonded<T>::type type;
326};
327
328
329template <typename T> struct
330remove_bonded_value
331{
332 typedef T type;
333};
334
335template <typename T, typename Reader> struct
336remove_bonded_value<bonded<T, Reader> >
337{
338 typedef T type;
339};
340
341template <typename T, typename Reader> struct
342remove_bonded_value<value<T, Reader> >
343{
344 typedef T type;
345};
346
347
348template <typename T> struct
349is_bond_type
350 : std::integral_constant<bool,
351 is_bonded<typename std::remove_const<T>::type>::value
352 || has_schema<typename std::remove_const<T>::type>::value> {};
353
354
355struct Unknown;
356
357template <typename Unused> struct
358schema<Unknown, Unused>
359{
360 struct type
361 {
362 typedef no_base base;
363 typedef boost::mpl::list<>::type fields;
364 static const Metadata metadata;
365
366 type()
367 {
368 (void)metadata;
369 }
370 };
371};
372
373template <typename Unused>
374const Metadata schema<Unknown, Unused>::type::metadata
375 = reflection::MetadataInit("Unknown", "Unknown", reflection::Attributes());
376
377template <typename T, typename Enable> struct
378schema_for_passthrough
379 : schema<typename remove_bonded<T>::type>
380{};
381
382template <typename T> struct
383schema_for_passthrough<T, typename boost::disable_if<has_schema<typename remove_bonded<T>::type> >::type>
384{
385 // If type T doesn't have schema we return schema of an empty struct;
386 // this allows pass-through of bonded<T> with only forward declaration for T.
387 typedef typename schema<Unknown>::type type;
388};
389
390template <typename T> struct
391is_container
392 : std::integral_constant<bool,
393 is_list_container<typename std::remove_const<T>::type>::value
394 || is_set_container<typename std::remove_const<T>::type>::value
395 || is_map_container<typename std::remove_const<T>::type>::value> {};
396
397
398template <typename Field, typename Transform, typename Enable = void> struct
399is_fast_path_field
400 : std::false_type {};
401
402
403template <typename Field, typename Transform> struct
404is_fast_path_field<Field, Transform, typename boost::enable_if<std::is_same<typename Field::struct_type,
405 typename Transform::FastPathType> >::type>
406 : std::true_type {};
407
408
409template <typename T> struct
410is_nested_field
411 : is_bond_type<typename T::field_type> {};
412
413
414template <typename T> struct
415is_struct_field
416 : has_schema<typename T::field_type> {};
417
418
419template <typename T1, typename T2, typename Enable = void> struct
420is_matching_container
421 : std::false_type {};
422
423
424template <typename T1, typename T2> struct
425is_matching_basic
426 : std::integral_constant<bool,
427 (is_string<T1>::value && is_string<T2>::value)
428 || (is_wstring<T1>::value && is_wstring<T2>::value)
429 || ((sizeof(T1) <= sizeof(T2))
430 && ((std::is_unsigned<T1>::value && std::is_unsigned<T2>::value)
431 || (is_signed_int_or_enum<T1>::value && is_signed_int_or_enum<T2>::value)))> {};
432
433
434template <typename T> struct
435is_matching_basic<typename aliased_type<T>::type, T>
436 : std::true_type {};
437
438
439template <typename T1, typename T2> struct
440is_matching
441 : std::integral_constant<bool,
442 (is_bond_type<T1>::value && is_bond_type<T2>::value)
443 || (is_matching_basic<T1, T2>::value)
444 || (is_matching_container<T1, T2>::value)> {};
445
446
447template <typename T> struct
448is_matching_basic<T, T>
449 : std::true_type {};
450
451
452template <> struct
453is_matching_basic<bool, bool>
454 : std::true_type {};
455
456
457template <typename T> struct
458is_matching_basic<bool, T>
459 : std::false_type {};
460
461
462template <> struct
463is_matching_basic<uint8_t, bool>
464 : std::false_type {};
465
466
467template <> struct
468is_matching_basic<float, double>
469 : std::true_type {};
470
471
472template <typename T, typename Enable> struct
473get_type_id;
474
475
476template <typename T1, typename T2> struct
477is_matching_container<T1, T2,
478 typename boost::enable_if_c<is_container<T1>::value
479 && get_type_id<T1>::value == get_type_id<T2>::value>::type>
480 : is_matching<typename element_type<T1>::type,
481 typename element_type<T2>::type> {};
482
483
484// tuples match if the elements match
485template <typename T1, typename T2, typename U1, typename U2> struct
486is_matching<std::pair<T1, T2>, std::pair<U1, U2> >
487 : std::integral_constant<bool,
488 is_matching<T1, U1>::value
489 && is_matching<T2, U2>::value> {};
490
491
492template <typename T1, typename T2> struct
493is_matching<std::pair<T1, T2>, std::pair<T1, T2> >
494 : std::true_type {};
495
496
497// value<T> matches if type matches
498template <typename T1, typename Reader, typename T2> struct
499is_matching<value<T1, Reader>, T2>
500 : is_matching<T1, T2> {};
501
502
503// value<void> matches every container
504template <typename T, typename Reader> struct
505is_matching<value<void, Reader>, T>
506 : is_container<T> {};
507
508
509template <typename T, typename X, typename Enable = void> struct
510is_element_matching
511 : std::false_type {};
512
513
514template <typename T, typename X> struct
515is_element_matching<T, X, typename boost::enable_if<is_container<X> >::type>
516 : is_matching<T, typename element_type<X>::type> {};
517
518
519template <typename X, typename Reader> struct
520is_element_matching<value<void, Reader>, X, typename boost::enable_if<is_container<X> >::type>
521 : std::integral_constant<bool,
522 is_bond_type<typename element_type<X>::type>::value
523 || is_container<typename element_type<X>::type>::value> {};
524
525
526template <typename T, typename X, typename Enable = void> struct
527is_map_element_matching
528 : std::false_type {};
529
530
531template <typename X, typename T> struct
532is_map_element_matching<T, X, typename boost::enable_if<is_map_container<X> >::type>
533 : is_matching<T, typename element_type<X>::type::second_type> {};
534
535
536template <typename X, typename Reader> struct
537is_map_element_matching<value<void, Reader>, X, typename boost::enable_if<is_map_container<X> >::type>
538 : std::integral_constant<bool,
539 is_bond_type<typename element_type<X>::type::second_type>::value
540 || is_container<typename element_type<X>::type::second_type>::value> {};
541
542
543template <typename T, typename X, typename Enable = void> struct
544is_map_key_matching
545 : std::false_type {};
546
547
548template <typename T, typename X> struct
549is_map_key_matching<T, X, typename boost::enable_if<is_map_container<X> >::type>
550 : is_matching<T, typename element_type<X>::type::first_type> {};
551
552
553template <typename T> struct
554is_basic_type
555 : std::integral_constant<bool,
556 !(is_container<T>::value || is_bond_type<T>::value)> {};
557
558template <> struct
559is_basic_type<void>
560 : std::false_type {};
561
562
563// is_nested_container
564template <typename T, typename Enable = void> struct
565is_nested_container
566 : std::false_type {};
567
568template <typename T> struct
569is_nested_container<T, typename boost::enable_if<is_map_container<T> >::type>
570 : std::integral_constant<bool,
571 !is_basic_type<typename element_type<T>::type::second_type>::value> {};
572
573
574template <typename T> struct
575is_nested_container<T, typename boost::enable_if<is_list_container<T> >::type>
576 : std::integral_constant<bool,
577 !is_basic_type<typename element_type<T>::type>::value> {};
578
579
580template <typename T, typename Enable = void> struct
581is_struct_container
582 : std::false_type {};
583
584template <typename T> struct
585is_struct_container<T, typename boost::enable_if<is_map_container<T> >::type>
586 : std::integral_constant<bool,
587 has_schema<typename element_type<T>::type::second_type>::value
588 || is_struct_container<typename element_type<T>::type::second_type>::value> {};
589
590
591
592template <typename T> struct
593is_struct_container<T, typename boost::enable_if<is_list_container<T> >::type>
594 : std::integral_constant<bool,
595 has_schema<typename element_type<T>::type>::value
596 || is_struct_container<typename element_type<T>::type>::value> {};
597
598
599// is_struct_container_field
600template <typename T> struct
601is_struct_container_field
602 : is_struct_container<typename T::field_type> {};
603
604
605// is_basic_container
606template <typename T, typename Enable = void> struct
607is_basic_container
608 : std::false_type {};
609
610template <typename T> struct
611is_basic_container<T, typename boost::enable_if<is_map_container<T> >::type>
612 : is_basic_type<typename element_type<T>::type::second_type> {};
613
614template <typename T> struct
615is_basic_container<T, typename boost::enable_if<is_list_container<T> >::type>
616 : is_basic_type<typename element_type<T>::type> {};
617
618template <typename T> struct
619is_basic_container<T, typename boost::enable_if<is_set_container<T> >::type>
620 : std::true_type {};
621
622
623template <typename T, typename F> struct
624is_matching_container_field
625 : is_matching_container<T, typename F::field_type> {};
626
627
628template <typename T> struct
629is_container_field
630 : is_container<typename T::field_type> {};
631
632
633template <typename T, typename F> struct
634is_matching_basic_field
635 : is_matching_basic<T, typename F::field_type> {};
636
637
638template <typename T, typename Reader> struct
639is_basic_type<value<T, Reader> >
640 : std::false_type {};
641
642
643template <typename T1, typename T2> struct
644is_basic_type<std::pair<T1, T2> >
645 : std::false_type {};
646
647
648template <typename T, typename X, typename Enable = void> struct
649matching_fields
650 : boost::mpl::copy_if<typename schema<T>::type::fields,
651 is_matching_basic_field<X, _>,
652 boost::mpl::front_inserter<boost::mpl::list<> > >
653{
654 BOOST_STATIC_ASSERT((is_basic_type<X>::value));
655};
656
657
658template <typename T, typename X> struct
659matching_fields<T, X, typename boost::enable_if<is_container<X> >::type>
660 : boost::mpl::copy_if<typename schema<T>::type::fields,
661 is_matching_container_field<X, _>,
662 boost::mpl::front_inserter<boost::mpl::list<> > > {};
663
664
665template <typename T> struct
666nested_fields
667 : boost::mpl::copy_if<typename schema<T>::type::fields,
668 is_nested_field<_>,
669 boost::mpl::front_inserter<boost::mpl::list<> > > {};
670
671
672template <typename T> struct
673struct_fields
674 : boost::mpl::copy_if<typename schema<T>::type::fields,
675 is_struct_field<_>,
676 boost::mpl::front_inserter<boost::mpl::list<> > > {};
677
678
679template <typename T> struct
680container_fields
681 : boost::mpl::copy_if<typename schema<T>::type::fields,
682 is_container_field<_>,
683 boost::mpl::front_inserter<boost::mpl::list<> > > {};
684
685
686template <typename T> struct
687has_base
688 : has_schema<typename schema<T>::type::base> {};
689
690
691template <typename T>
692BondDataType
693GetTypeId(const T&)
694{
695 return get_type_id<T>::value;
696}
697
698
699template <typename Reader>
700BondDataType
701GetTypeId(const value<void, Reader>& value)
702{
703 return value.GetTypeId();
704}
705
706
707template <typename T, typename Reader> struct
708get_type_id<value<T, Reader> >
709 : get_type_id<T> {};
710
711
712template <typename T1, typename T2> struct
713get_type_id<std::pair<T1, T2> >
714{
715 static const std::pair<BondDataType, BondDataType> value;
716};
717
718template <typename T1, typename T2>
719const std::pair<BondDataType, BondDataType>
720get_type_id<std::pair<T1, T2> >::value = std::make_pair(
721 get_type_id<typename std::remove_const<T1>::type>::value,
722 get_type_id<T2>::value);
723
724template <> struct
725get_type_id<bool>
726 : std::integral_constant<BondDataType, BT_BOOL> {};
727
728template <> struct
729get_type_id<uint8_t>
730 : std::integral_constant<BondDataType, BT_UINT8> {};
731
732template <> struct
733get_type_id<uint16_t>
734 : std::integral_constant<BondDataType, BT_UINT16> {};
735
736template <> struct
737get_type_id<uint32_t>
738 : std::integral_constant<BondDataType, BT_UINT32> {};
739
740template <> struct
741get_type_id<uint64_t>
742 : std::integral_constant<BondDataType, BT_UINT64> {};
743
744template <> struct
745get_type_id<int8_t>
746 : std::integral_constant<BondDataType, BT_INT8> {};
747
748template <> struct
749get_type_id<int16_t>
750 : std::integral_constant<BondDataType, BT_INT16> {};
751
752template <> struct
753get_type_id<int32_t>
754 : std::integral_constant<BondDataType, BT_INT32> {};
755
756template <> struct
757get_type_id<int64_t>
758 : std::integral_constant<BondDataType, BT_INT64> {};
759
760template <> struct
761get_type_id<float>
762 : std::integral_constant<BondDataType, BT_FLOAT> {};
763
764template <> struct
765get_type_id<double>
766 : std::integral_constant<BondDataType, BT_DOUBLE> {};
767
768template <> struct
769get_type_id<void>
770 : std::integral_constant<BondDataType, BT_UNAVAILABLE> {};
771
772template <typename T> struct
773get_type_id<T, typename boost::enable_if<std::is_enum<T>>::type>
774 : get_type_id<int32_t> {};
775
776template <typename T> struct
777get_type_id<T, typename boost::enable_if<is_bond_type<T>>::type>
778 : std::integral_constant<BondDataType, BT_STRUCT> {};
779
780template <typename T> struct
781get_type_id<T, typename boost::enable_if<is_set_container<typename std::remove_const<T>::type>>::type>
782 : std::integral_constant<BondDataType, BT_SET> {};
783
784template <typename T> struct
785get_type_id<T, typename boost::enable_if<is_map_container<typename std::remove_const<T>::type>>::type>
786 : std::integral_constant<BondDataType, BT_MAP> {};
787
788template <typename T> struct
789get_type_id<T, typename boost::enable_if<is_list_container<typename std::remove_const<T>::type>>::type>
790 : std::integral_constant<BondDataType, BT_LIST> {};
791
792template <typename T> struct
793get_type_id<T, typename boost::enable_if<is_string<typename std::remove_const<T>::type>>::type>
794 : std::integral_constant<BondDataType, BT_STRING> {};
795
796template <typename T> struct
797get_type_id<T, typename boost::enable_if<is_wstring<typename std::remove_const<T>::type>>::type>
798 : std::integral_constant<BondDataType, BT_WSTRING> {};
799
800template <typename T, typename Enable> struct
801get_type_id
802 : get_type_id<typename aliased_type<T>::type> {};
803
804
805template <typename T, typename Enable = void> struct
806get_list_sub_type_id
807 : std::integral_constant<ListSubType, NO_SUBTYPE> {};
808
809template <typename T> struct
810get_list_sub_type_id<nullable<T> >
811 : std::integral_constant<ListSubType, NULLABLE_SUBTYPE> {};
812
813template <> struct
814get_list_sub_type_id<blob>
815 : std::integral_constant<ListSubType, BLOB_SUBTYPE> {};
816
817
818class PrimitiveTypes
819{
820 struct Init
821 {
822 Init(uint32_t* _sizeof)
823 : _sizeof(_sizeof)
824 {}
825
826 template <typename T>
827 void operator()(const T&)
828 {
829 _sizeof[get_type_id<T>::value] = sizeof(T);
830 }
831
832 uint32_t* _sizeof;
833 };
834
835public:
836 typedef boost::mpl::list
837 <
838 bool, float, double,
839 uint8_t, uint16_t, uint32_t, uint64_t,
840 int8_t, int16_t, int32_t, int64_t
841 >type;
842
843 PrimitiveTypes(uint32_t* _sizeof)
844 {
845 boost::mpl::for_each<type>(Init(_sizeof));
846 }
847};
848
849} // namespace bond
namespace bond
Definition: apply.h:17
Field description in compile-time schema.
Definition: reflection.h:73
static value_type & GetVariable(struct_type &object)
Static method returning reference to the field value for a particular object.
Definition: reflection.h:115
static const field_pointer field
Static data member representing the field pointer.
Definition: reflection.h:101
Struct struct_type
Type of the field's parent struct.
Definition: reflection.h:78
FieldType value_type
Type of the field value.
Definition: reflection.h:87
static const value_type & GetVariable(const struct_type &object)
Static method returning const reference to the field value for a particular object.
Definition: reflection.h:108
FieldType Struct::* field_pointer
Type of the field pointer.
Definition: reflection.h:81
ModifierTag field_modifier
Modifier tag for the field.
Definition: reflection.h:95
remove_maybe< FieldType >::type field_type
Type of the field.
Definition: reflection.h:84
static const Metadata & metadata
Static data member describing field metadata.
Definition: reflection.h:98