Bond
 
Loading...
Searching...
No Matches
protocol_visitors.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 "pass_through.h"
9#include "tags.h"
10
11#include <bond/core/customize.h>
12#include <bond/core/null.h>
13#include <bond/core/protocol.h>
14#include <bond/core/traits.h>
15#include <bond/stream/input_buffer.h>
17
18#include <cstddef>
19
20
21namespace bond
22{
23
24class RuntimeSchema;
25struct SchemaReader;
26
27template <typename Writer, typename Protocols>
28class Serializer;
29
30namespace detail
31{
32
33// Visitor which applies protocol's parser to specified transform and data.
34// It is used to dispatch to appropriate protocol at runtime.
35template <typename T, typename Schema, typename Transform>
36class _Parser
37 : boost::noncopyable
38{
39public:
40 _Parser(const Transform& transform, const Schema& schema)
41 : _transform(transform),
42 _schema(schema)
43 {}
44
45
46 template <typename Reader>
47 typename boost::enable_if<is_protocol_enabled<typename std::remove_const<Reader>::type>, bool>::type
48 operator()(Reader& reader) const
49 {
50 // Apply transform to serialized data
51 return Apply(_transform, reader, _schema, false);
52 }
53
54 template <typename Reader>
55 typename boost::disable_if<is_protocol_enabled<typename std::remove_const<Reader>::type>, bool>::type
56 operator()(Reader& /*reader*/) const
57 {
58 // Don't instantiate deserialization code for disabled protocol to speed up build
59 BOOST_ASSERT(false);
60 return false;
61 }
62
63 template <typename Reader, typename Writer, typename Protocols>
64 static
65 typename boost::enable_if_c<is_protocol_same<Reader, Writer>::value
66 && protocol_has_multiple_versions<Reader>::value, bool>::type
67 Apply(const Serializer<Writer, Protocols>& transform, Reader& reader, const Schema& schema, bool base)
68 {
69 if (is_protocol_version_same(reader, transform._output))
70 return FastPassThrough(reader, transform._output, schema);
71 else
72 return typename Reader::Parser(reader, base).Apply(transform, schema);
73 }
74
75 template <typename Reader, typename Writer, typename Protocols>
76 static
77 typename boost::enable_if_c<is_protocol_same<Reader, Writer>::value
78 && !protocol_has_multiple_versions<Reader>::value, bool>::type
79 Apply(const Serializer<Writer, Protocols>& transform, Reader& reader, const Schema& schema, bool base)
80 {
81 BOOST_VERIFY(!base);
82 // Triggering the following assert means that bond::enable_protocol_versions trait is
83 // defined/specialized inconsistently for the protocol in different compilation units.
84 BOOST_ASSERT(is_protocol_version_same(reader, transform._output));
85 return FastPassThrough(reader, transform._output, schema);
86 }
87
88 template <typename TransformT, typename Reader>
89 static
90 bool Apply(const TransformT& transform, Reader& reader, const Schema& schema, bool base)
91 {
92 return typename Reader::Parser(reader, base).Apply(transform, schema);
93 }
94
95protected:
96 template <typename Reader, typename Writer, typename SchemaT>
97 static
98 bool FastPassThrough(Reader& reader, Writer& writer, const SchemaT&)
99 {
100 bonded<T, Reader&> value(reader);
101 PassThrough(value, reader, writer);
102 return false;
103 }
104
105 template <typename Reader, typename Writer>
106 static
107 bool FastPassThrough(Reader& reader, Writer& writer, const RuntimeSchema& schema)
108 {
109 bonded<void, Reader&> value(reader, schema);
110 PassThrough(value, reader, writer);
111 return false;
112 }
113
114 const Transform& _transform;
115 const Schema& _schema;
116};
117
118
119template <typename T, typename Schema, typename Transform, typename Enable = void>
120class Parser
121 : public _Parser<T, Schema, Transform>
122{
123public:
124 Parser(const Transform& transform, const Schema& schema)
125 : _Parser<T, Schema, Transform>(transform, schema)
126 {}
127
128 using _Parser<T, Schema, Transform>::operator();
129
130 bool operator()(ValueReader& value) const
131 {
132 // "De-serializing" bonded<T> containing a non-serialized instance of T
133 BOOST_VERIFY(value.pointer == NULL);
134 return false;
135 }
136};
137
138
139template <typename T, typename Schema, typename Transform>
140class Parser<T, Schema, Transform, typename boost::enable_if_c<is_serializing_transform<Transform>::value && !std::is_same<T, void>::value>::type>
141 : public _Parser<T, Schema, Transform>
142{
143public:
144 Parser(const Transform& transform, const Schema& schema)
145 : _Parser<T, Schema, Transform>(transform, schema)
146 {}
147
148 using _Parser<T, Schema, Transform>::operator();
149
150 bool operator()(ValueReader& value) const
151 {
152 // Serializing bonded<T> containing a non-serialized instance of T
153 BOOST_ASSERT(value.pointer);
154 // NOTE TO USER: following assert may indicate that the generated file
155 // _reflection.h was not included in compilation unit where T is serialized.
156 BOOST_ASSERT(has_schema<T>::value);
157 return StaticParser<const T&>(*static_cast<const T*>(value.pointer)).Apply(_transform, typename schema_for_passthrough<T>::type());
158 }
159
160protected:
161 using _Parser<T, Schema, Transform>::_transform;
162};
163
164
165template <typename Reader, typename T>
166inline void Skip(Reader& reader, const bonded<T, Reader&>& bonded)
167{
168 reader.Skip(bonded);
169}
170
171
172template <typename T, template <typename BufferT, typename MarshaledBondedProtocolsT> class Reader, typename Buffer, typename MarshaledBondedProtocols>
173inline void Skip(const bonded<T, Reader<Buffer, MarshaledBondedProtocols>&>& bonded)
174{
175 // Skip the structure field-by-field by applying Null transform
176 Apply<MarshaledBondedProtocols>(Null(), bonded);
177}
178
179
180template <typename Reader, typename T>
181BOND_NO_INLINE void Skip(Reader& reader, const bonded<T, Reader&>& bonded, const std::nothrow_t&) BOND_NOEXCEPT
182{
183 try
184 {
185 Skip(reader, bonded);
186 }
187 catch(...)
188 {}
189}
190
191template <typename T>
192void Skip(SchemaReader&, const bonded<T, SchemaReader&>&, const std::nothrow_t&) BOND_NOEXCEPT
193{}
194
195
196template <typename T>
197inline void Skip(ProtocolReader& /*reader*/, const bonded<T>& /*bonded*/) BOND_NOEXCEPT
198{
199 // Not skipping for outer structures
200}
201
202
203template <typename T>
204inline void Skip(ProtocolReader& /*reader*/, const bonded<T>& /*bonded*/, const std::nothrow_t&) BOND_NOEXCEPT
205{
206 // Not skipping for outer structures
207}
208
209
210template <typename T, typename Protocols, typename Transform, typename Reader, typename Schema>
211inline bool Parse(const Transform& transform, Reader& reader, const Schema& schema, const RuntimeSchema* runtime_schema, bool base)
212{
213 BOOST_VERIFY(!runtime_schema);
214 return Parser<T, Schema, Transform>::Apply(transform, reader, schema, base);
215}
216
217template <typename T, typename Protocols, typename Transform, typename Reader, typename Schema>
218inline bool Parse(const Transform& transform, Reader& reader, const Schema& schema, std::nullptr_t, bool base)
219{
220 return Parser<T, Schema, Transform>::Apply(transform, reader, schema, base);
221}
222
223template <typename T, typename Protocols, typename Transform, typename Schema>
224inline bool Parse(const Transform& transform, ProtocolReader& reader, const Schema& schema)
225{
226 // Use named variable to avoid gcc silently copying objects (which
227 // causes build break, because Parser<> is non-copyable).
228 Parser<T, Schema, Transform> parser(transform, schema);
229
230 if (auto&& result = reader.template Visit<Protocols
231#if defined(BOND_NO_CXX14_RETURN_TYPE_DEDUCTION) || defined(BOND_NO_CXX14_GENERIC_LAMBDAS)
232 , bool
233#endif
234 >(parser))
235 {
236 return result.get();
237 }
238
239 UnknownProtocolException();
240}
241
242template <typename T, typename Protocols, typename Transform, typename Schema>
243inline bool Parse(const Transform& transform, ProtocolReader reader, const Schema& schema, const RuntimeSchema* runtime_schema, bool base)
244{
245 BOOST_VERIFY(!base);
246
247 if (runtime_schema)
248 {
249 return Parse<void, Protocols>(transform, reader, *runtime_schema);
250 }
251 else
252 {
253 return Parse<T, Protocols>(transform, reader, schema);
254 }
255}
256
257template <typename T, typename Protocols, typename Transform, typename Schema>
258inline bool Parse(const Transform& transform, ProtocolReader reader, const Schema& schema, std::nullptr_t, bool base)
259{
260 BOOST_VERIFY(!base);
261 return Parse<T, Protocols>(transform, reader, schema);
262}
263
264
265// Visitor which updates in-situ bonded<T> payload by merging it with an object.
266template <typename T, typename Buffer>
267class InsituMerge
268 : boost::noncopyable
269{
270public:
271 InsituMerge(const T& var, ProtocolReader& reader)
272 : _var(var),
273 _reader(reader)
274 {}
275
276
277 template <typename Reader>
278 typename boost::enable_if<is_protocol_enabled<typename std::remove_const<Reader>::type> >::type
279 operator()(Reader& reader) const
280 {
281 Buffer merged;
282 typename get_protocol_writer<Reader, Buffer>::type writer(merged);
283
284 Merge(_var, reader, writer);
285
286 _reader = Reader(merged.GetBuffer());
287 }
288
289 template <typename Reader>
290 typename boost::disable_if<is_protocol_enabled<typename std::remove_const<Reader>::type> >::type
291 operator()(Reader& /*reader*/) const
292 {
293 // Don't instantiate code for disabled protocol to speed up build
294 BOOST_ASSERT(false);
295 }
296
297
298 void operator()(ValueReader&) const
299 {
300 // Merge is undefined for non-serialized instance of T
301 BOOST_VERIFY(false);
302 }
303
304private:
305 const T& _var;
306 ProtocolReader& _reader;
307};
308
309
310template <typename Protocols, typename Buffer = OutputBuffer, typename T>
311inline void Merge(const T& var, ProtocolReader& reader)
312{
313 if (!reader.template Visit<Protocols
314#if defined(BOND_NO_CXX14_RETURN_TYPE_DEDUCTION) || defined(BOND_NO_CXX14_GENERIC_LAMBDAS)
315 , void
316#endif
317 >(InsituMerge<T, Buffer>(var, reader)))
318 {
319 UnknownProtocolException();
320 }
321}
322
323
324} // namespace detail
325
326} // namespace bond
namespace bond
Definition: apply.h:17
void Merge(const T &obj, Reader input, Writer &output)
Merge an object with serialize data and write the result using a protocol writer.
Definition: bond.h:125