Bond
 
Loading...
Searching...
No Matches
rapidjson_helper.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 "rapidjson_utils.h"
9
10#include <bond/core/bond_const_enum.h>
11#include <bond/core/bond_types.h>
12#include <bond/core/detail/sdl.h>
13#include <bond/core/exception.h>
14
15#define RAPIDJSON_NO_INT64DEFINE
16#define RAPIDJSON_ASSERT BOOST_ASSERT
17#define RAPIDJSON_PARSE_ERROR(err, offset) bond::RapidJsonException(rapidjson::GetParseError_En(err), offset)
18
19#include "rapidjson/rapidjson.h"
20#include "rapidjson/error/en.h"
21
22// rapidjson/document.h v1.1 uses std::min/max in ways that conflict
23// with macros defined in windows. This works around the issue.
24#ifdef _MSC_VER
25#if defined(_WINDEF_) || defined(_MINWINDEF_)
26#ifndef NOMINMAX
27 #pragma push_macro("min")
28 #pragma push_macro("max")
29#undef min
30#undef max
31#endif
32#endif
33#endif
34
35#include "rapidjson/document.h"
36
37#ifdef _MSC_VER
38#if defined(_WINDEF_) || defined(_MINWINDEF_)
39#ifndef NOMINMAX
40 #pragma pop_macro("min")
41 #pragma pop_macro("max")
42#endif
43#endif
44#endif
45
46#include "rapidjson/writer.h"
47
48#include <boost/noncopyable.hpp>
49
50#include <algorithm>
51
52namespace bond
53{
54namespace detail
55{
56
57
58// Adapter from Bond input stream to rapidjson read-only stream
59template <typename Buffer>
60class RapidJsonInputStream
61{
62public:
63 typedef char Ch;
64
65 explicit RapidJsonInputStream(const Buffer& input)
66 : _input(input),
67 _current(0),
68 _count(0)
69 {
70 _input.Read(_current);
71 }
72
73 const Buffer& GetBuffer() const
74 {
75 return _input;
76 }
77
78 Buffer& GetBuffer()
79 {
80 return _input;
81 }
82
83 char Peek()
84 {
85 if (!_current)
86 {
87 _input.Read(_current);
88 }
89
90 return _current;
91 }
92
93 size_t Tell() const
94 {
95 return _count;
96 }
97
98 char Take()
99 {
100 char c = _current;
101 _current = '\0';
102
103 if (!c)
104 {
105 _input.Read(c);
106 }
107
108 ++_count;
109 return c;
110 }
111
112 // not implemented for read only stream
113 char* PutBegin() { BOOST_ASSERT(false); return 0; }
114 void Put(char) { BOOST_ASSERT(false); }
115 size_t PutEnd(char*) { BOOST_ASSERT(false); return 0; }
116
117private:
118 Buffer _input;
119 uint8_t _current;
120 size_t _count;
121};
122
123
124// Adapter from Bond output stream to rapidjson write-only stream
125template <typename Buffer>
126class RapidJsonOutputStream
127{
128public:
129 explicit RapidJsonOutputStream(Buffer& output)
130 : _output(output)
131 {
132 }
133
134 typedef char Ch;
135
136 // not implemented for write-only stream
137 char Peek() { BOOST_ASSERT(false); return 0; }
138 size_t Tell() const { BOOST_ASSERT(false); return 0; }
139 char Take() { BOOST_ASSERT(false); return 0; }
140 size_t PutEnd(char* begin) { BOOST_ASSERT(false); return 0; }
141 char* PutBegin() { BOOST_ASSERT(false); return 0; }
142
143 void Put(char c)
144 {
145 _output.Write(c);
146 }
147
148 void Flush()
149 {
150 }
151
152private:
153 Buffer& _output;
154};
155
156
157// Specialization to allow using string as input buffer for simple JSON reader
158template <>
159struct RapidJsonInputStream<const rapidjson::UTF8<>::Ch*> : rapidjson::StringStream
160{
161 explicit RapidJsonInputStream(const char* buffer)
162 : rapidjson::StringStream(buffer)
163 {}
164
165 RapidJsonInputStream(const RapidJsonInputStream& that, const char*)
166 : rapidjson::StringStream(that)
167 {}
168};
169
170
171class JsonTypeMatching : boost::noncopyable
172{
173public:
174 JsonTypeMatching(BondDataType type, BondDataType schema, bool is_enum)
175 : matchesObject(type == BT_STRUCT && type == schema),
176 matchesArray((type == BT_MAP || type == BT_LIST || type == BT_SET) && type == schema),
177 matchesNull(type == BT_LIST && type == schema),
178 matchesInt(type >= BT_INT8 && type <= BT_INT64),
179 matchesInt64(type == BT_INT64),
180 matchesUint(type >= BT_UINT8 && type <= BT_UINT64),
181 matchesUint64(type == BT_UINT64),
182 matchesNumber(type >= BT_FLOAT && type <= BT_DOUBLE),
183 matchesString(type == BT_STRING || type == BT_WSTRING || is_enum),
184 matchesBool(type == BT_BOOL)
185 {}
186
187
188 bool TypeMatch(const rapidjson::Value& value) const
189 {
190 return ComplexTypeMatch(value) || BasicTypeMatch(value);
191 }
192
193 bool ComplexTypeMatch(const rapidjson::Value& value) const
194 {
195 return ((value.IsObject() && matchesObject)
196 || (value.IsArray() && matchesArray)
197 || (value.IsNull() && matchesNull));
198 }
199
200 bool BasicTypeMatch(const rapidjson::Value& value) const
201 {
202 return ((value.IsString() && matchesString)
203 || (value.IsUint() && matchesUint)
204 || (value.IsInt() && matchesInt)
205 || (value.IsUint64() && matchesUint64)
206 || (value.IsInt64() && matchesInt64)
207 || (value.IsNumber() && matchesNumber)
208 || (value.IsBool() && matchesBool));
209 }
210
211private:
212 const bool matchesObject;
213 const bool matchesArray;
214 const bool matchesNull;
215 const bool matchesInt;
216 const bool matchesInt64;
217 const bool matchesUint;
218 const bool matchesUint64;
219 const bool matchesNumber;
220 const bool matchesString;
221 const bool matchesBool;
222};
223
224
225// bool
226inline void Read(const rapidjson::Value& value, bool& var)
227{
228 var = value.GetBool();
229}
230
231// enum
232template <typename T>
233typename boost::enable_if<std::is_enum<T> >::type
234Read(const rapidjson::Value& value, T& var)
235{
236 if (value.IsString())
237 ToEnum(var, value.GetString());
238 else
239 var = static_cast<T>(value.GetInt());
240}
241
242// floating point
243template <typename T>
244typename boost::enable_if<std::is_floating_point<T> >::type
245Read(const rapidjson::Value& value, T& var)
246{
247 var = static_cast<T>(value.GetDouble());
248}
249
250// signed integer
251template <typename T>
252typename boost::enable_if<is_signed_int<T> >::type
253Read(const rapidjson::Value& value, T& var)
254{
255 var = static_cast<T>(value.GetInt64());
256}
257
258// unsigned integer
259template <typename T>
260typename boost::enable_if<std::is_unsigned<T> >::type
261Read(const rapidjson::Value& value, T& var)
262{
263 var = static_cast<T>(value.GetUint64());
264}
265
266// strings
267template <typename T>
268typename boost::enable_if<is_string<T> >::type
269Read(const rapidjson::Value& value, T& var)
270{
271 const uint32_t length = value.GetStringLength();
272 resize_string(var, length);
273
274 std::copy(make_checked_array_iterator(value.GetString(), length),
275 make_checked_array_iterator(value.GetString(), length, length),
276 make_checked_array_iterator(string_data(var), length));
277}
278
279
280// wstring
281template <typename T>
282typename boost::enable_if<is_wstring<T> >::type
283Read(const rapidjson::Value& value, T& var)
284{
285 const std::basic_string<uint16_t> str = utf_to_utf(
286 value.GetString(),
287 value.GetString() + value.GetStringLength());
288
289 const size_t length = str.size();
290 resize_string(var, static_cast<uint32_t>(length));
291
292 std::copy(
293 str.begin(),
294 str.end(),
295 make_checked_array_iterator(string_data(var), length));
296}
297
298
299// type alias
300template <typename T>
301typename boost::enable_if<is_type_alias<T> >::type
302Read(const rapidjson::Value& value, T& var)
303{
304 typename aliased_type<T>::type x;
305 Read(value, x);
306 set_aliased_value(var, x);
307}
308
309
310template <typename Reader>
311value<void, Reader&>
312MakeValue(Reader& reader, const value<void, Reader&>& element)
313{
314 return value<void, Reader&>(reader, element.GetRuntimeSchema());
315}
316
317template <typename Reader, typename T>
318value<T, Reader&>
319MakeValue(Reader& reader, const value<T, Reader&>&)
320{
321 return value<T, Reader&>(reader);
322}
323
324inline const std::string& FieldName(const Metadata& metadata)
325{
326 std::map<std::string, std::string>::const_iterator it
327 = metadata.attributes.find("JsonName");
328
329 if (it != metadata.attributes.end())
330 return it->second;
331
332 return metadata.name;
333}
334
335} // namespace detail
336
337} // namespace bond
namespace bond
Definition: apply.h:17