Bond
 
Loading...
Searching...
No Matches
validate.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
8namespace bond
9{
10namespace detail
11{
12
13inline bool ValidateType(BondDataType src, BondDataType dst)
14{
15 switch (src)
16 {
17 case BT_UINT8:
18 case BT_UINT16:
19 case BT_UINT32:
20 switch (dst)
21 {
22 case BT_UINT16:
23 case BT_UINT32:
24 case BT_UINT64:
25 return src <= dst;
26 default:
27 break;
28 }
29 break;
30
31 case BT_INT8:
32 case BT_INT16:
33 case BT_INT32:
34 switch (dst)
35 {
36 case BT_INT16:
37 case BT_INT32:
38 case BT_INT64:
39 return src <= dst;
40 default:
41 break;
42 }
43 break;
44
45 case BT_FLOAT:
46 return (dst == BT_DOUBLE);
47
48 default:
49 break;
50 }
51
52 return (src == dst);
53}
54
55struct struct_list
56{
57 const struct_list* last;
58 const StructDef* dst;
59 const StructDef* src;
60};
61
62inline void ValidateStruct(const RuntimeSchema& src,
63 const RuntimeSchema& dst,
64 const struct_list* list,
65 bool& identical);
66
67inline bool ValidateType(const RuntimeSchema& src,
68 const RuntimeSchema& dst,
69 const struct_list* list,
70 bool& identical)
71{
72 if (dst.GetTypeId() != src.GetTypeId())
73 {
74 identical = false;
75 return ValidateType(src.GetTypeId(), dst.GetTypeId());
76 }
77
78 if (dst.GetType().bonded_type != src.GetType().bonded_type)
79 {
80 identical = false;
81 }
82
83 if (dst.GetTypeId() == BT_STRUCT && !dst.GetType().bonded_type)
84 {
85 ValidateStruct(src, dst, list, identical);
86 return true;
87 }
88
89 if (!dst.GetType().element.empty())
90 {
91 RuntimeSchema r_dst(dst, *dst.GetType().element);
92 RuntimeSchema r_src(src, *src.GetType().element);
93
94 if (!ValidateType(r_src, r_dst, list, identical))
95 {
96 return false;
97 }
98 }
99
100 if (!dst.GetType().key.empty())
101 {
102 RuntimeSchema r_dst(dst, *dst.GetType().key);
103 RuntimeSchema r_src(src, *src.GetType().key);
104
105 if (!ValidateType(r_src, r_dst, list, identical))
106 {
107 return false;
108 }
109 }
110
111 return true;
112}
113
114inline void ValidateFields(const RuntimeSchema& src,
115 const RuntimeSchema& dst,
116 const struct_list* list,
117 bool& identical)
118{
119 const StructDef& s_dst = dst.GetStruct();
120 const StructDef& s_src = src.GetStruct();
121
122 size_t n_dst = s_dst.fields.size();
123 size_t n_src = s_src.fields.size();
124
125 if (n_dst != n_src)
126 {
127 identical = false;
128 }
129
130 for (size_t i_dst = 0, i_src = 0; i_dst < n_dst; )
131 {
132 const FieldDef* f_dst = &s_dst.fields[i_dst];
133 const FieldDef* f_src = (i_src < n_src) ? &s_src.fields[i_src] : NULL;
134
135 if (f_src && f_src->id < f_dst->id)
136 {
137 i_src++;
138 continue;
139 }
140
141 if (!f_src || f_src->id > f_dst->id)
142 {
143 if (f_dst->metadata.modifier == Required)
144 {
145 RequiredFieldMissingException(s_dst, *f_dst);
146 }
147
148 i_dst++;
149 continue;
150 }
151
152 if (f_dst->metadata.modifier == Required &&
153 f_src->metadata.modifier == Optional)
154 {
155 OptionalToRequiredException(s_src, s_dst, *f_src, *f_dst);
156 }
157
158 if (!ValidateType(RuntimeSchema(src, *f_src),
159 RuntimeSchema(dst, *f_dst),
160 list, identical))
161 {
162 FieldTypeIncompatibleException(s_src, s_dst, *f_src, *f_dst);
163 }
164
165 i_dst++;
166 i_src++;
167 }
168}
169
170inline void ValidateStruct(const RuntimeSchema& src,
171 const RuntimeSchema& dst,
172 const struct_list* list,
173 bool& identical)
174{
175 struct_list next = {
176 list, &dst.GetStruct(), &src.GetStruct()
177 };
178
179 for (; list; list = list->last)
180 {
181 if (list->dst == next.dst &&
182 list->src == next.src)
183 {
184 return;
185 }
186 }
187
188 uint16_t d_dst = schema_depth(dst);
189 uint16_t d_src = schema_depth(src);
190
191 if (d_dst > d_src)
192 {
193 StructBaseDifferentException(src.GetStruct(), dst.GetStruct());
194 }
195
196 if (d_src > d_dst)
197 {
198 return ValidateStruct(src.GetBaseSchema(), dst, &next, identical = false);
199 }
200
201 if (dst.HasBase())
202 {
203 ValidateStruct(src.GetBaseSchema(), dst.GetBaseSchema(), &next, identical);
204 }
205
206 ValidateFields(src, dst, &next, identical);
207}
208
209
210// Checks if payload contains unknown fields
211template <typename Protocols>
212class SchemaValidator
213 : public DeserializingTransform
214{
215public:
216 void Begin(const Metadata&) const
217 {}
218
219 void End() const
220 {}
221
222 void UnknownEnd() const
223 {}
224
225 template <typename T>
226 bool Base(const T& value) const
227 {
228 return Recurse(value);
229 }
230
231 template <typename T>
232 bool Field(uint16_t, const Metadata&, const T& value) const
233 {
234 return Recurse(value);
235 }
236
237 template <typename T>
238 [[noreturn]] bool UnknownField(uint16_t id, const T&) const
239 {
240 UnknownSchemaDefException(id);
241 }
242
243 template <typename T>
244 void Container(const T& element, uint32_t size) const
245 {
246 while (size--)
247 Recurse(element);
248 }
249
250 template <typename Key, typename T>
251 void Container(const Key&, const T& value, uint32_t size) const
252 {
253 while (size--)
254 Recurse(value);
255 }
256
257private:
258 template <typename T>
259 bool Recurse(const T&) const
260 {
261 return false;
262 }
263
264 template <typename T, typename Reader>
265 typename boost::enable_if<is_basic_type<T>, bool>::type
266 Recurse(const value<T, Reader>&) const
267 {
268 return false;
269 }
270
271 template <typename T, typename Reader>
272 typename boost::disable_if<is_basic_type<T>, bool>::type
273 Recurse(const value<T, Reader>& value) const
274 {
275 Apply<Protocols>(*this, value);
276 return false;
277 }
278
279 template <typename T, typename Reader>
280 bool Recurse(const bonded<T, Reader>& value) const
281 {
282 return Apply<Protocols>(*this, value);
283 }
284};
285
286} // namespace detail
287} // namespace bond
namespace bond
Definition: apply.h:17