Bond
 
All Classes Namespaces Files Functions Variables Typedefs Friends Pages
Loading...
Searching...
No Matches
simple_json_reader.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 "detail/rapidjson_helper.h"
9#include "encoding.h"
10
11#include "rapidjson/document.h"
12#include "rapidjson/reader.h"
13
14#include <boost/make_shared.hpp>
15#include <boost/none.hpp>
16#include <boost/optional/optional.hpp>
17
18namespace bond
19{
20
21template <typename BufferT>
23
24
26template <typename BufferT>
28{
29public:
30 typedef BufferT Buffer;
31 typedef DOMParser<SimpleJsonReader&> Parser;
32 typedef SimpleJsonWriter<Buffer> Writer;
33 typedef rapidjson::Value Field;
34
35 BOND_STATIC_CONSTEXPR uint16_t magic = SIMPLE_JSON_PROTOCOL;
36 BOND_STATIC_CONSTEXPR uint16_t version = 0x0001;
37
39 SimpleJsonReader(const Buffer& input)
40 : _value(nullptr),
41 _document(boost::make_shared<rapidjson::Document>()),
42 _streamHolder(input)
43 { }
44
49 SimpleJsonReader(SimpleJsonReader& parent, const Field& value)
50 : _value(&value),
51 _document(parent._document),
52 _streamHolder(parent)
53 {
54 // Must have an already-parsed parent
55 BOOST_ASSERT(parent._value);
56 }
57
58 bool ReadVersion()
59 {
60 return false;
61 }
62
63 void Parse()
64 {
65 // Don't need to reparse for nested fields
66 if (!_value || _value == _document.get())
67 {
68 const unsigned parseFlags = rapidjson::kParseIterativeFlag | rapidjson::kParseStopWhenDoneFlag;
69
70 _document->ParseStream<parseFlags>(_streamHolder.Get());
71
72 // If there were any parse errors, an exception should have been
73 // thrown, as we define RAPIDJSON_PARSE_ERROR
74 BOOST_ASSERT(!_document->HasParseError());
75 _value = _document.get();
76 }
77 }
78
79 const Field* FindField(uint16_t id, const Metadata& metadata, BondDataType type)
80 {
81 // BT_INT32 may be an enum. This allows us to decode symbolic enum values
82 // when parsing using runtime schema. The assumption is that runtime schema
83 // matches JSON payload. If it doesn't, nothing horrible will happen, but
84 // we might not indicate a required field missing for an int32 field if we
85 // mistake a string member with matching name for it.
86 return FindField(id, metadata, type, type == BT_INT32);
87 }
88
89 const Field* FindField(uint16_t id, const Metadata& metadata, BondDataType type, bool is_enum);
90
91
92 template <typename T>
93 void Read(T& var)
94 {
95 detail::Read(*GetValue(), var);
96 }
97
98 // Does the reader have enough input buffer left to read an array of T?
99 template<typename T>
100 bool CanReadArray(uint32_t /*num_elems*/) const
101 {
102 return true;
103 }
104
105 template <typename T>
106 void ReadContainerBegin(uint32_t&, T&)
107 {
108 BOOST_ASSERT(false);
109 }
110
111 void ReadContainerEnd()
112 {
113 BOOST_ASSERT(false);
114 }
115
116 template <typename T>
117 void Skip()
118 { }
119
120 template <typename T>
121 void Skip(const T&)
122 { }
123
124
125 bool operator==(const SimpleJsonReader& rhs) const
126 {
127 return _value == rhs._value;
128 }
129
131 const Buffer& GetBuffer() const
132 {
133 return _streamHolder.Get().GetBuffer();
134 }
135
137 Buffer& GetBuffer()
138 {
139 return _streamHolder.Get().GetBuffer();
140 }
141
142private:
143 rapidjson::Value::ConstMemberIterator MemberBegin() const
144 {
145 return GetValue()->IsObject() ? GetValue()->MemberBegin() : rapidjson::Value::ConstMemberIterator();
146 }
147
148 rapidjson::Value::ConstMemberIterator MemberEnd() const
149 {
150 return GetValue()->IsObject() ? GetValue()->MemberEnd() : rapidjson::Value::ConstMemberIterator();
151 }
152
153 rapidjson::Value::ConstValueIterator ArrayBegin() const
154 {
155 return GetValue()->IsArray() ? GetValue()->Begin() : rapidjson::Value::ConstValueIterator();
156 }
157
158 rapidjson::Value::ConstValueIterator ArrayEnd() const
159 {
160 return GetValue()->IsArray() ? GetValue()->End() : rapidjson::Value::ConstValueIterator();
161 }
162
163 uint32_t ArraySize() const
164 {
165 return GetValue()->IsArray() ? GetValue()->Size() : 0;
166 }
167
168 const rapidjson::Value* GetValue() const
169 {
170 BOOST_ASSERT(_value);
171 return _value;
172 }
173
174 template <typename Input>
175 friend struct base_input;
176
177 template <typename Protocols, typename A, typename T, typename Buffer>
178 friend void DeserializeContainer(std::vector<bool, A>&, const T&, SimpleJsonReader<Buffer>&);
179
180 template <typename Protocols, typename T, typename Buffer>
181 friend void DeserializeContainer(blob&, const T&, SimpleJsonReader<Buffer>&);
182
183 template <typename Protocols, typename X, typename T, typename Buffer>
184 friend typename boost::enable_if<is_list_container<X> >::type
185 DeserializeContainer(X&, const T&, SimpleJsonReader<Buffer>&);
186
187 template <typename Protocols, typename X, typename T, typename Buffer>
188 friend typename boost::enable_if<is_set_container<X> >::type
189 DeserializeContainer(X&, const T&, SimpleJsonReader<Buffer>&);
190
191 template <typename Protocols, typename X, typename T, typename Buffer>
192 friend typename boost::enable_if<is_map_container<X> >::type
193 DeserializeMap(X&, BondDataType, const T&, SimpleJsonReader<Buffer>&);
194
195 const rapidjson::Value* _value;
196 boost::shared_ptr<rapidjson::Document> _document;
197
200 class StreamHolder
201 {
202 public:
203 explicit StreamHolder(const Buffer& input)
204 : _stream(),
205 _parent()
206 {
207 // could use boost::in_place to construct this in the
208 // initializer list when the minimum version of Boost is 1.63
209 _stream.emplace(input);
210 BOOST_ASSERT(IsParent());
211 }
212
213 explicit StreamHolder(SimpleJsonReader& parent)
214 : _stream(),
215 // Resolve the real parent
216 _parent(&parent._streamHolder.GetParent())
217 {
218 BOOST_ASSERT(_parent->IsParent());
219 BOOST_ASSERT(!IsParent());
220 }
221
222 // Intentionaly deep copy. Copies of SimpleJsonReader are expected
223 // to be deep copies, even if they're made from children.
224 StreamHolder(const StreamHolder& other)
225 : _stream(other.Get()),
226 _parent()
227 {
228 BOOST_ASSERT(IsParent());
229 }
230
231 StreamHolder& operator=(const StreamHolder& other)
232 {
233 _stream.emplace(other.Get());
234 _parent = nullptr;
235 BOOST_ASSERT(IsParent());
236
237 return *this;
238 }
239
240 StreamHolder(StreamHolder&&) = default;
241 StreamHolder& operator=(StreamHolder&&) = default;
242
243 const detail::RapidJsonInputStream<Buffer>& Get() const
244 {
245 return IsParent() ? _stream.value() : _parent->Get();
246 }
247
248 detail::RapidJsonInputStream<Buffer>& Get()
249 {
250 return IsParent() ? _stream.value() : _parent->Get();
251 }
252
253 private:
254 bool IsParent() const
255 {
256 const bool isParent = _parent == nullptr;
257 BOOST_ASSERT(isParent == static_cast<bool>(_stream)); // parents must have a stream
258 return isParent;
259 }
260
261 StreamHolder& GetParent()
262 {
263 return IsParent() ? *this : *_parent;
264 }
265
266 boost::optional<detail::RapidJsonInputStream<Buffer>> _stream;
267 StreamHolder* _parent;
268 } _streamHolder;
269};
270
271
272template <typename Buffer>
273BOND_CONSTEXPR_OR_CONST uint16_t SimpleJsonReader<Buffer>::magic;
274
275// Disable fast pass-through optimization for Simple JSON
276template <typename Input, typename Output> struct
277is_protocol_same<SimpleJsonReader<Input>, SimpleJsonWriter<Output> >
278 : std::false_type {};
279
280
281} // namespace bond
SimpleJsonReader(SimpleJsonReader &parent, const Field &value)
Create a "child" SimpleJsonReader to read value, which is known to be a member of the document in par...
Definition simple_json_reader.h:49
Buffer & GetBuffer()
Access to underlying buffer.
Definition simple_json_reader.h:137
SimpleJsonReader(const Buffer &input)
Construct from input buffer/stream containing serialized data.
Definition simple_json_reader.h:39
const Buffer & GetBuffer() const
Access to underlying buffer.
Definition simple_json_reader.h:131
Writer for Simple JSON.
Definition simple_json_writer.h:26
namespace bond
Definition apply.h:17