Bond
 
Loading...
Searching...
No Matches
inheritance.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 "omit_default.h"
9
10namespace bond
11{
12
13
14template <typename Input>
15struct base_input
16{
17 BOOST_STATIC_ASSERT(std::is_reference<Input>::value);
18 typedef Input type;
19 static type from(type input)
20 {
21 return input;
22 }
23};
24
25
26namespace detail
27{
28
29template <typename T, typename Enable = void> struct
30hierarchy_depth
31 : std::integral_constant<uint16_t, 1> {};
32
33
34template <typename T> struct
35hierarchy_depth<T, typename boost::enable_if<std::is_class<typename schema<typename T::base>::type> >::type>
36 : std::integral_constant<uint16_t, 1 + hierarchy_depth<typename schema<typename T::base>::type>::value> {};
37
38
39template <typename T> struct
40expected_depth
41 : std::integral_constant<uint16_t, 0xffff> {};
42
43
44template <typename T, typename Protocols, typename Validator> struct
45expected_depth<bond::To<T, Protocols, Validator> >
46 : hierarchy_depth<typename schema<T>::type> {};
47
48
49template <typename Base, typename T>
50inline Base& base_cast(T& obj)
51{
52 return static_cast<Base&>(obj);
53}
54
55
56template <typename Base, typename T>
57inline const Base& base_cast(const T& obj)
58{
59 return static_cast<const Base&>(obj);
60}
61
62
63template <typename Input, typename Parser>
64class ParserInheritance
65 : boost::noncopyable
66{
67protected:
68 ParserInheritance(Input input, bool base)
69 : _input(input),
70 _base(base)
71 {}
72
73 // use compile-time schema
74 template <typename T, typename Transform>
75 typename boost::enable_if_c<(hierarchy_depth<T>::value > expected_depth<Transform>::value), bool>::type
76 Read(const T&, const Transform& transform)
77 {
78 typename base_input<Input>::type base(base_input<Input>::from(_input));
79
80 // The hierarchy of the payload schema is deeper than what the transform "expects".
81 // We recursively find the matching level to start parsing from.
82 // After we finish parsing the expected parts of the hierarchy, we give
83 // the parser a chance to skip the unexpected parts.
84 detail::StructBegin(_input, true);
85
86 bool result = Parser(base, _base).Read(typename schema<typename T::base>::type(), transform);
87
88 detail::StructEnd(_input, true);
89
90 static_cast<Parser*>(this)->SkipFields(typename boost::mpl::begin<typename T::fields>::type());
91
92 return result;
93 }
94
95
96 template <typename T, typename Transform>
97 typename boost::disable_if_c<(hierarchy_depth<T>::value > expected_depth<Transform>::value), bool>::type
98 Read(const T&, const Transform& transform)
99 {
100 // We are at the expected level within the hierarchy.
101 // First we recurse into base structs (serialized data starts at the top of the hierarchy)
102 // and then we read to the transform the fields of the top level struct.
103 transform.Begin(T::metadata);
104
105 bool done = ReadBase(base_class<T>(), transform);
106
107 if (!done)
108 {
109 done = static_cast<Parser*>(this)->ReadFields(typename boost::mpl::begin<typename T::fields>::type(), transform);
110 }
111
112 transform.End();
113
114 return done;
115 }
116
117
118 template <typename Base, typename Transform>
119 typename boost::enable_if<is_reader<Input, Base>, bool>::type
120 ReadBase(const Base*, const Transform& transform)
121 {
122 typename base_input<Input>::type base(base_input<Input>::from(_input));
123
124 return transform.Base(bonded<Base, Input>(base, true));
125 }
126
127
128 template <typename Base, typename Transform>
129 typename boost::disable_if<is_reader<Input, Base>, bool>::type
130 ReadBase(const Base*, const Transform& transform)
131 {
132 return transform.Base(base_cast<Base>(_input));
133 }
134
135
136 template <typename Transform>
137 bool ReadBase(const no_base*, const Transform&)
138 {
139 return false;
140 }
141
142
143 // use runtime schema
144 template <typename Transform>
145 bool Read(const RuntimeSchema& schema, const Transform& transform)
146 {
147 // The logic is the same as for compile-time schemas, described in the comments above.
148 bool done;
149
150 typename base_input<Input>::type base(base_input<Input>::from(_input));
151
152 if (schema_depth(schema) > expected_depth<Transform>::value)
153 {
154 BOOST_ASSERT(schema.HasBase());
155
156 detail::StructBegin(_input, true);
157
158 done = Parser(base, _base).Read(schema.GetBaseSchema(), transform);
159
160 detail::StructEnd(_input, true);
161
162 static_cast<Parser*>(this)->SkipFields(schema);
163 }
164 else
165 {
166 transform.Begin(schema.GetStruct().metadata);
167
168 done = schema.HasBase() && transform.Base(bonded<void, Input>(base, schema.GetBaseSchema(), true));
169
170 if (!done)
171 {
172 done = static_cast<Parser*>(this)->ReadFields(schema, transform);
173 }
174
175 transform.End();
176 }
177
178 return done;
179 }
180
181 Input _input;
182 const bool _base;
183};
184
185} // namespace detail
186
187} // namespace bond
namespace bond
Definition: apply.h:17