Bond
 
Loading...
Searching...
No Matches
omit_default.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/bond_fwd.h>
7#include <bond/core/maybe.h>
8#include <bond/core/reflection.h>
9#include <bond/core/stl_containers.h>
10#include <bond/core/traits.h>
11#include "odr.h"
12
13#include <boost/utility/enable_if.hpp>
14
15namespace bond
16{
17
18
19namespace detail
20{
21
22
23// default for maybe<T> is 'nothing'
24template <typename T>
25inline
26bool is_default(const maybe<T>& value, const Metadata& /*metadata*/)
27{
28 return value.is_nothing();
29}
30
31
32// compare basic fields with default value from metadata
33template <typename T>
34inline
35typename boost::enable_if_c<is_basic_type<T>::value
36 && !is_string_type<T>::value
37 && !is_type_alias<T>::value, bool>::type
38is_default(const T& value, const Metadata& metadata)
39{
40 return (metadata.default_value == value);
41}
42
43
44// compare wire value of type alias fields with default value from metadata
45template <typename T>
46inline
47typename boost::enable_if<is_type_alias<T>, bool>::type
48is_default(const T& value, const Metadata& metadata)
49{
50 return (metadata.default_value == get_aliased_value(value));
51}
52
53
54// compare string fields with default value from metadata
55template <typename T>
56inline
57typename boost::enable_if<is_string<typename std::remove_const<T>::type>, bool>::type
58is_default(const T& value, const Metadata& metadata)
59{
60 BOOST_ASSERT(!metadata.default_value.nothing);
61 return !metadata.default_value.string_value.compare(0, std::string::npos, string_data(value), string_length(value));
62}
63
64
65template <typename T>
66inline
67typename boost::enable_if<is_wstring<typename std::remove_const<T>::type>, bool>::type
68is_default(const T& value, const Metadata& metadata)
69{
70 BOOST_ASSERT(!metadata.default_value.nothing);
71 return !metadata.default_value.wstring_value.compare(0, std::wstring::npos, string_data(value), string_length(value));
72}
73
74
75// for containers default value is always empty
76template <typename T>
77inline
78typename boost::enable_if<is_container<T>, bool>::type
79is_default(const T& value, const Metadata& /*metadata*/)
80{
81 return (container_size(value) == 0);
82}
83
84
85// structs don't have default value
86template <typename T>
87inline
88typename boost::enable_if<is_bond_type<T>, bool>::type
89is_default(const T& /*value*/, const Metadata& /*metadata*/)
90{
91 return false;
92}
93
94
95// return true if the field may be omitted during serialization
96template <typename Writer, typename T>
97inline
98typename boost::enable_if<may_omit_fields<Writer>, bool>::type
99omit_field(const Metadata& metadata, const T& value)
100{
101 // Validate that all compilation units in a program use the same
102 // specialization of may_omit_fields<Writer>
103 (void)one_definition<may_omit_fields<Writer>, std::true_type>::value;
104
105 // omit the field if it's optional and has default value
106 return metadata.modifier == Optional
107 && is_default(value, metadata);
108}
109
110
111template <typename Writer, typename T>
112inline
113typename boost::disable_if<may_omit_fields<Writer>, bool>::type
114omit_field(const Metadata& /*metadata*/, const T& /*value*/)
115{
116 // Validate that all compilation units in a program use the same
117 // specialization of may_omit_fields<Writer>
118 (void)one_definition<may_omit_fields<Writer>, std::false_type>::value;
119
120 // protocol doesn't allow omitting fields
121 return false;
122}
123
124
125// when transcoding from one protocol to another fields are never omitted
126template <typename Writer, typename Reader, typename T>
127inline
128bool omit_field(const Metadata& /*metadata*/, const value<T, Reader>& /*value*/)
129{
130 return false;
131}
132
133
134template <typename T, typename Enable = void> struct
135implements_field_omitting
136 : std::false_type {};
137
138
139#ifdef BOND_NO_SFINAE_EXPR
140template <typename T> struct
141implements_field_omitting<T&>
142 : implements_field_omitting<T> {};
143#endif
144
145
146// WriteFieldOmitted is an optional protocol writer method which is called for
147// omitted optional fields. It CAN be implemented by tagged protocols and MUST
148// be implemented by untagged protocols that allow omitting optional fields.
149template <typename Writer> struct
150implements_field_omitting<Writer,
151#ifdef BOND_NO_SFINAE_EXPR
152 typename boost::enable_if<check_method<void (Writer::*)(BondDataType, uint16_t, const Metadata&), &Writer::WriteFieldOmitted> >::type>
153#else
154 detail::mpl::void_t<decltype(std::declval<Writer>().WriteFieldOmitted(
155 std::declval<BondDataType>(),
156 std::declval<uint16_t>(),
157 std::declval<Metadata>()))>>
158#endif
159 : std::true_type {};
160
161
162// ReadFieldOmitted is an optional protocol reader method which MUST be implemented
163// by untagged protocols that allow omitting optional fields.
164template <typename Input> struct
165implements_field_omitting<Input,
166#ifdef BOND_NO_SFINAE_EXPR
167 typename boost::enable_if<check_method<bool (Input::*)(), &Input::ReadFieldOmitted> >::type>
168#else
169 typename boost::enable_if<std::is_same<
170 bool,
171 decltype(std::declval<Input>().ReadFieldOmitted())>>::type>
172#endif
173 : std::true_type {};
174
175
176// WriteFieldOmitted
177template <typename Writer>
178typename boost::enable_if<implements_field_omitting<Writer> >::type
179WriteFieldOmitted(Writer& output, BondDataType type, uint16_t id, const Metadata& metadata)
180{
181 output.WriteFieldOmitted(type, id, metadata);
182}
183
184
185template <typename Writer>
186typename boost::disable_if<implements_field_omitting<Writer> >::type
187WriteFieldOmitted(Writer& /*output*/, BondDataType /*type*/, uint16_t /*id*/, const Metadata& /*metadata*/)
188{}
189
190
191// ReadFieldOmitted
192template <typename Input>
193typename boost::enable_if<implements_field_omitting<Input>, bool>::type
194ReadFieldOmitted(Input& input)
195{
196 return input.ReadFieldOmitted();
197}
198
199
200template <typename Input>
201typename boost::disable_if<implements_field_omitting<Input>, bool>::type
202ReadFieldOmitted(Input& /*input*/)
203{
204 return false;
205}
206
207
208// ReadStructBegin and ReadStructEnd are optional methods for protocol
209template <typename T, typename Enable = void> struct
210implements_struct_begin
211 : std::false_type {};
212
213
214// Intially ReadStructBegin/End methods had no parameters but later were extended
215// to take a bool parameter indicating deserialization of base part of a struct.
216template <typename T, typename Enable = void> struct
217implements_struct_begin_with_base
218 : std::false_type {};
219
220
221template <typename Input> struct
222implements_struct_begin<Input,
223#ifdef BOND_NO_SFINAE_EXPR
224 typename boost::enable_if<check_method<void (Input::*)(), &Input::ReadStructBegin> >::type>
225#else
226 detail::mpl::void_t<decltype(std::declval<Input>().ReadStructBegin())>>
227#endif
228 : std::true_type {};
229
230
231template <typename Input> struct
232implements_struct_begin_with_base<Input,
233#ifdef BOND_NO_SFINAE_EXPR
234 typename boost::enable_if<check_method<void (Input::*)(bool), &Input::ReadStructBegin> >::type>
235#else
236 detail::mpl::void_t<decltype(std::declval<Input>().ReadStructBegin(std::declval<bool>()))>>
237#endif
238 : std::true_type {};
239
240
241// StructBegin
242template <typename Input>
243typename boost::enable_if_c<implements_struct_begin<Input>::value
244 && !implements_struct_begin_with_base<Input>::value>::type
245StructBegin(Input& input, bool /*base*/)
246{
247 return input.ReadStructBegin();
248}
249
250
251template <typename Input>
252typename boost::enable_if<implements_struct_begin_with_base<Input> >::type
253StructBegin(Input& input, bool base)
254{
255 return input.ReadStructBegin(base);
256}
257
258
259template <typename Input>
260typename boost::disable_if_c<implements_struct_begin<Input>::value
261 || implements_struct_begin_with_base<Input>::value>::type
262StructBegin(Input& /*input*/, bool /*base*/)
263{}
264
265
266// StructEnd
267template <typename Input>
268typename boost::enable_if_c<implements_struct_begin<Input>::value
269 && !implements_struct_begin_with_base<Input>::value>::type
270StructEnd(Input& input, bool /*base*/)
271{
272 return input.ReadStructEnd();
273}
274
275
276template <typename Input>
277typename boost::enable_if<implements_struct_begin_with_base<Input> >::type
278StructEnd(Input& input, bool base)
279{
280 return input.ReadStructEnd(base);
281}
282
283
284template <typename Input>
285typename boost::disable_if_c<implements_struct_begin<Input>::value
286 || implements_struct_begin_with_base<Input>::value>::type
287StructEnd(Input& /*input*/, bool /*base*/)
288{}
289
290
291} // namespace detail
292
293
294// It is OK to omit optional fields with default values for all tagged protocols
295// and for untagged protocols which implement field omitting support.
296template <typename T> struct
297may_omit_fields
298 : std::integral_constant<bool,
299 !uses_static_parser<typename T::Reader>::value
300 || detail::implements_field_omitting<T>::value> {};
301
302} // namespace bond
namespace bond
Definition: apply.h:17