Bond
 
Loading...
Searching...
No Matches
select_protocol.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 "exception.h"
9#include "protocol.h"
10#include "runtime_schema.h"
11#include "select_protocol_fwd.h"
12
13#ifdef BOND_NO_CXX14_GENERIC_LAMBDAS
14#include <functional>
15#endif
16
17
18namespace bond
19{
20namespace detail
21{
22
23
24// Overload of Apply used to extract bonded<T> from marshaled payload
25template <typename Protocols, typename T, typename U, typename Reader>
26inline bool
27Apply(const boost::reference_wrapper<bonded<T> >& ref, const bonded<U, Reader>& value)
28{
29 value.template Deserialize<Protocols>(ref.get());
30 return false;
31}
32
33
34template <typename Protocols, typename F>
35inline auto TryEachProtocol(F&& f)
36#ifdef BOND_NO_CXX14_RETURN_TYPE_DEDUCTION
37 -> decltype(mpl::try_apply<typename Protocols::type>(std::forward<F>(f)))
38#endif
39{
40 return mpl::try_apply<typename Protocols::type>(std::forward<F>(f));
41}
42
43
44template <typename T, typename Protocols>
45struct NextProtocolFunctor
46{
47 template <typename Buffer, typename Transform, typename Reader>
48 boost::optional<std::pair<ProtocolType, bool> >
49 operator()(Buffer& input, const Transform& transform, const mpl::identity<Reader>&) const
50 {
51 Reader reader(input);
52
53 if (reader.ReadVersion())
54 {
55 return std::make_pair(
56 static_cast<ProtocolType>(Reader::magic),
57 Apply<Protocols>(transform, bonded<T, ProtocolReader>(reader)));
58 }
59
60 return {};
61 }
62
63 template <typename Buffer, typename Transform, typename Reader>
64 boost::optional<bool>
65 operator()(Buffer& input, const Transform& transform, uint16_t protocol, const mpl::identity<Reader>&) const
66 {
67 if (Reader::magic == protocol)
68 {
69 Reader reader(input);
70 return Apply<Protocols>(transform, bonded<T, Reader&>(reader));
71 }
72
73 return {};
74 }
75
76
77 template <template <typename Writer, typename ProtocolsT> class Transform>
78 struct TransformFunctor
79 {
80 template <typename Buffer, typename Reader>
81 boost::optional<bool>
82 operator()(const T& value, Buffer& output, uint16_t protocol, const mpl::identity<Reader>&) const
83 {
84 if (Reader::magic == protocol)
85 {
86 using Writer = typename get_protocol_writer<Reader, Buffer>::type;
87
88 Writer writer(output);
89 return Apply<Protocols>(Transform<Writer, Protocols>(writer), value);
90 }
91
92 return {};
93 }
94 };
95};
96
97
98template <typename Protocols>
99struct NextProtocolFunctor<void, Protocols>
100{
101 template <typename Buffer, typename Transform, typename Reader>
102 boost::optional<std::pair<ProtocolType, bool> >
103 operator()(const RuntimeSchema& schema, Buffer& input, const Transform& transform, const mpl::identity<Reader>&) const
104 {
105 Reader reader(input);
106
107 if (reader.ReadVersion())
108 {
109 return std::make_pair(
110 static_cast<ProtocolType>(Reader::magic),
111 Apply<Protocols>(transform, bonded<void, ProtocolReader>(reader, schema)));
112 }
113
114 return {};
115 }
116
117 template <typename Buffer, typename Transform, typename Reader>
118 boost::optional<bool>
119 operator()(const RuntimeSchema& schema, Buffer& input, const Transform& transform, uint16_t protocol, const mpl::identity<Reader>&) const
120 {
121 if (Reader::magic == protocol)
122 {
123 Reader reader(input);
124 return Apply<Protocols>(transform, bonded<void, Reader&>(reader, schema));
125 }
126
127 return {};
128 }
129};
130
131
132// Select protocol and apply transform using compile-time schema
133template <typename T, typename Protocols, typename Buffer, typename Transform>
134inline std::pair<ProtocolType, bool> NextProtocol(Buffer& input, const Transform& transform)
135{
136 auto&& visitor =
137#ifndef BOND_NO_CXX14_GENERIC_LAMBDAS
138 [&](const auto& identity) { return NextProtocolFunctor<T, Protocols>{}(input, transform, identity); };
139#else
140 std::bind(NextProtocolFunctor<T, Protocols>{}, std::ref(input), std::cref(transform), std::placeholders::_1);
141#endif
142
143 if (auto&& result = TryEachProtocol<typename Protocols::template FilterBuffer<Buffer> >(std::move(visitor)))
144 {
145 return result.get();
146 }
147
148 UnknownProtocolException();
149}
150
151
152// Select protocol and apply transform using runtime schema
153template <typename Protocols, typename Buffer, typename Transform>
154inline std::pair<ProtocolType, bool> NextProtocol(const RuntimeSchema& schema, Buffer& input, const Transform& transform)
155{
156 auto&& visitor =
157#ifndef BOND_NO_CXX14_GENERIC_LAMBDAS
158 [&](const auto& identity) { return NextProtocolFunctor<void, Protocols>{}(schema, input, transform, identity); };
159#else
160 std::bind(NextProtocolFunctor<void, Protocols>{}, std::cref(schema), std::ref(input), std::cref(transform), std::placeholders::_1);
161#endif
162
163 if (auto&& result = TryEachProtocol<typename Protocols::template FilterBuffer<Buffer> >(std::move(visitor)))
164 {
165 return result.get();
166 }
167
168 UnknownProtocolException();
169}
170
171
172// Select protocol based on magic number and apply transform using compile-time schema
173template <typename T, typename Protocols, typename Buffer, typename Transform>
174inline bool NextProtocol(Buffer& input, const Transform& transform, uint16_t protocol)
175{
176 auto&& visitor =
177#ifndef BOND_NO_CXX14_GENERIC_LAMBDAS
178 [&](const auto& identity) { return NextProtocolFunctor<T, Protocols>{}(input, transform, protocol, identity); };
179#else
180 std::bind(NextProtocolFunctor<T, Protocols>{}, std::ref(input), std::cref(transform), protocol, std::placeholders::_1);
181#endif
182
183 if (auto&& result = TryEachProtocol<typename Protocols::template FilterBuffer<Buffer> >(std::move(visitor)))
184 {
185 return result.get();
186 }
187
188 UnknownProtocolException(protocol);
189}
190
191
192// Select protocol based on magic number and apply transform using runtime schema
193template <typename Protocols, typename Buffer, typename Transform>
194inline bool NextProtocol(const RuntimeSchema& schema, Buffer& input, const Transform& transform, uint16_t protocol)
195{
196 auto&& visitor =
197#ifndef BOND_NO_CXX14_GENERIC_LAMBDAS
198 [&](const auto& identity) { return NextProtocolFunctor<void, Protocols>{}(schema, input, transform, protocol, identity); };
199#else
200 std::bind(NextProtocolFunctor<void, Protocols>{}, std::cref(schema), std::ref(input), std::cref(transform), protocol, std::placeholders::_1);
201#endif
202
203 if (auto&& result = TryEachProtocol<typename Protocols::template FilterBuffer<Buffer> >(std::move(visitor)))
204 {
205 return result.get();
206 }
207
208 UnknownProtocolException(protocol);
209}
210
211
212// Select protocol based on magic number and apply instance of serializing transform
213template <template <typename Writer, typename ProtocolsT> class Transform, typename Protocols, typename T, typename Buffer>
214inline bool NextProtocol(const T& value, Buffer& output, uint16_t protocol)
215{
216 using TransformFunctor = typename NextProtocolFunctor<T, Protocols>::template TransformFunctor<Transform>;
217
218 auto&& visitor =
219#ifndef BOND_NO_CXX14_GENERIC_LAMBDAS
220 [&](const auto& identity) { return TransformFunctor{}(value, output, protocol, identity); };
221#else
222 std::bind(TransformFunctor{}, std::cref(value), std::ref(output), protocol, std::placeholders::_1);
223#endif
224
225 if (auto&& result = TryEachProtocol<typename Protocols::FilterEnabled>(std::move(visitor)))
226 {
227 return result.get();
228 }
229
230 UnknownProtocolException(protocol);
231}
232
233
234} // namespace detail
235
236
237//
238// Apply transform to serialized data that was generated using Marshaler
239//
240
241
242// Use compile-time schema
243template <typename T, typename Protocols, typename Buffer, typename Transform>
244inline std::pair<ProtocolType, bool> SelectProtocolAndApply(Buffer& input, const Transform& transform)
245{
246 return detail::NextProtocol<T, Protocols>(input, transform);
247}
248
249
250// Use runtime schema
251template <typename Protocols, typename Buffer, typename Transform>
252inline std::pair<ProtocolType, bool> SelectProtocolAndApply(
253 const RuntimeSchema& schema,
254 Buffer& input,
255 const Transform& transform)
256{
257 return detail::NextProtocol<Protocols>(schema, input, transform);
258}
259
260
261// Apply deserializing transform with a protocol specified by magic number
262// Use compile-time schema
263template <typename T, typename Protocols = BuiltInProtocols, typename Transform, typename Buffer>
264inline bool Apply(const Transform& transform, Buffer& input, uint16_t protocol)
265{
266 return detail::NextProtocol<T, Protocols>(input, transform, protocol);
267}
268
269
270// Use runtime schema
271template <typename Protocols = BuiltInProtocols, typename Transform, typename Buffer>
272inline bool Apply(const Transform& transform, const RuntimeSchema& schema, Buffer& input, uint16_t protocol)
273{
274 return detail::NextProtocol<Protocols>(schema, input, transform, protocol);
275}
276
277
278// Apply an instance of serializing transform with a protocol specified by magic number
279template <template <typename Writer, typename ProtocolsT> class Transform, typename Protocols = BuiltInProtocols, typename T, typename Buffer>
280inline bool Apply(const T& value, Buffer& output, uint16_t protocol)
281{
282 return detail::NextProtocol<Transform, Protocols>(value, output, protocol);
283}
284
285
286} // namespace bond
287
288
289#ifdef BOND_LIB_TYPE
290#if BOND_LIB_TYPE != BOND_LIB_TYPE_HEADER
291#include "detail/select_protocol_extern.h"
292#endif
293#else
294#error BOND_LIB_TYPE is undefined
295#endif
namespace bond
Definition: apply.h:17