Bond
 
Loading...
Searching...
No Matches
simple_json_writer.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 <bond/core/transforms.h>
12
13namespace bond
14{
15
16
17template <typename Buffer>
18class SimpleJsonReader;
19
20
22template <typename BufferT>
24 : protected rapidjson::Writer<detail::RapidJsonOutputStream<BufferT> >,
25 boost::noncopyable
26{
27public:
28 typedef BufferT Buffer;
30
36 SimpleJsonWriter(Buffer& output, bool pretty = false, int indent = 4, bool all_fields = true)
37 : rapidjson::Writer<detail::RapidJsonOutputStream<BufferT> >(_stream),
38 _stream(output),
39 _output(output),
40 _count(0),
41 _level(0),
42 _indent((std::min)(indent, 8)),
43 _pretty(pretty),
44 _all_fields(all_fields)
45 {}
46
48 typename boost::call_traits<Buffer>::reference
50 {
51 return _output;
52 }
53
54 void WriteVersion()
55 {}
56
57 void WriteOpen(char bracket)
58 {
59 _output.Write(bracket);
60 ++_level;
61 _count = 0;
62 }
63
64 void WriteClose(char bracket)
65 {
66 --_level;
67 ++_count;
68 NewLine();
69 _output.Write(bracket);
70 }
71
72 template <typename T>
73 typename boost::enable_if<is_string_type<T> >::type
74 WriteName(const T& name)
75 {
76 WriteString(name);
77 _output.Write(": ", _pretty ? 2 : 1);
78 }
79
80 void WriteName(uint16_t id)
81 {
82 _output.Write('\"');
83 this->WriteUint(id);
84 _output.Write("\": ", _pretty ? 3 : 2);
85 }
86
87 void Write(bool value)
88 {
89 if (value)
90 _output.Write("true", 4);
91 else
92 _output.Write("false", 5);
93 }
94
95 template <typename T>
96 typename boost::enable_if<is_string_type<T> >::type
97 Write(const T& value)
98 {
99 WriteString(value);
100 }
101
102 template <typename T>
103 typename boost::enable_if<is_signed_int<T> >::type
104 Write(T value)
105 {
106 this->WriteInt64(value);
107 }
108
109 template <typename T>
110 typename boost::enable_if<std::is_unsigned<T> >::type
111 Write(T value)
112 {
113 this->WriteUint64(value);
114 }
115
116 void Write(double value)
117 {
118 this->WriteDouble(value);
119 }
120
121 template <typename T>
122 typename boost::enable_if<std::is_enum<T> >::type
123 Write(const T& value)
124 {
125 this->WriteInt(static_cast<int>(value));
126 }
127
128 template <typename T>
129 typename boost::enable_if<is_type_alias<T> >::type
130 Write(const T& value)
131 {
132 Write(get_aliased_value(value));
133 }
134
135 void WriteNull()
136 {
137 _output.Write("null", 4);
138 }
139
140 void WriteSeparator(const int per_line = 1)
141 {
142 if (_count)
143 _output.Write(", ", _pretty ? 2 : 1);
144
145 if (_count++ % per_line == 0)
146 NewLine();
147 }
148
149private:
150 using rapidjson::Writer<detail::RapidJsonOutputStream<BufferT> >::WriteString;
151
152 template <typename T>
153 typename boost::enable_if<is_string<T> >::type
154 WriteString(const T& value)
155 {
156 WriteString(string_data(value), string_length(value));
157 }
158
159 template <typename T>
160 typename boost::enable_if<is_wstring<T> >::type
161 WriteString(const T& value)
162 {
163 _output.Write('\"');
164 for (const wchar_t *p = string_data(value), *end = p + string_length(value); p < end; ++p)
165 {
166 wchar_t c = *p;
167
168 if (c < L'\x20' || c == '"' || c == '\\' || c == '/')
169 {
170 switch (c)
171 {
172 case L'\b': c = L'b'; break;
173 case L'\f': c = L'f'; break;
174 case L'\n': c = L'n'; break;
175 case L'\r': c = L'r'; break;
176 case L'\t': c = L't'; break;
177 }
178
179 if (c >= L'\x20')
180 _output.Write('\\');
181 }
182
183 if (c >= L'\x20' && c < L'\x80')
184 {
185 _output.Write(static_cast<char>(c));
186 }
187 else
188 {
189 WriteUnicode(c);
190 }
191 }
192 _output.Write('\"');
193 }
194
195 void WriteUnicode(wchar_t c)
196 {
197 char u[6] = "\\u";
198 u[2] = detail::HexDigit(static_cast<int>(c >> 12));
199 u[3] = detail::HexDigit(static_cast<int>(c >> 8));
200 u[4] = detail::HexDigit(static_cast<int>(c >> 4));
201 u[5] = detail::HexDigit(static_cast<int>(c >> 0));
202 _output.Write(u, sizeof(u));
203 }
204
205 void NewLine()
206 {
207 if (!_pretty)
208 return;
209
210 _output.Write('\n');
211 for (int i = _level; i--;)
212 _output.Write(" ", _indent);
213 }
214
215 template <typename Writer, typename Protocols>
216 friend class Serializer;
217
218 detail::RapidJsonOutputStream<BufferT> _stream;
219 Buffer& _output;
220 int _count;
221 int _level;
222 const int _indent;
223 const bool _pretty;
224 const bool _all_fields;
225};
226
227
228template <typename Buffer> struct
229is_writer<SimpleJsonWriter<Buffer>, void>
230 : std::true_type {};
231
232
233template <typename Buffer, typename Protocols>
234class Serializer<SimpleJsonWriter<Buffer>, Protocols>
235 : public SerializingTransform
236{
237public:
238 typedef SimpleJsonWriter<Buffer> writer_type;
239
240 Serializer(writer_type& writer)
241 : _output(writer),
242 _level(0)
243 {}
244
245 void Begin(const Metadata& /*metadata*/) const
246 {
247 if (!_level++)
248 _output.WriteOpen('{');
249 }
250
251 void End() const
252 {
253 WriteEnd(--_level != 0);
254 }
255
256 void UnknownEnd() const
257 {
258 WriteEnd(true);
259 }
260
261 template <typename T>
262 bool Base(const T& value) const
263 {
264 Apply<Protocols>(*this, value);
265 return false;
266 }
267
268 template <typename T>
269 bool Field(uint16_t /*id*/, const Metadata& metadata, const maybe<T>& value) const
270 {
271 if (!value.is_nothing())
272 {
273 WriteName(detail::FieldName(metadata));
274 Write(value.value());
275 }
276 return false;
277 }
278
279 template <typename T>
280 bool Field(uint16_t /*id*/, const Metadata& metadata, const T& value) const
281 {
282 if (_output._all_fields
283 || !detail::omit_field<writer_type>(metadata, value))
284 {
285 WriteName(detail::FieldName(metadata));
286 Write(value);
287 }
288 return false;
289 }
290
291 template <typename T>
292 bool UnknownField(uint16_t id, const T& value) const
293 {
294 WriteName(id);
295 Write(value);
296 return false;
297 }
298
299 bool OmittedField(uint16_t id, const Metadata& metadata, BondDataType type) const
300 {
301 if (_output._all_fields && !metadata.default_value.nothing)
302 {
303 switch (type)
304 {
305 case BT_BOOL:
306 Field(id, metadata, !!metadata.default_value.uint_value);
307 break;
308 case BT_UINT8:
309 case BT_UINT16:
310 case BT_UINT32:
311 case BT_UINT64:
312 Field(id, metadata, metadata.default_value.uint_value);
313 break;
314 case BT_FLOAT:
315 case BT_DOUBLE:
316 Field(id, metadata, metadata.default_value.double_value);
317 break;
318 case BT_STRING:
319 Field(id, metadata, metadata.default_value.string_value);
320 break;
321 case BT_STRUCT:
322 BOOST_ASSERT(false);
323 break;
324 case BT_LIST:
325 case BT_SET:
326 WriteName(detail::FieldName(metadata));
327 _output.WriteOpen('[');
328 _output.WriteClose(']');
329 break;
330 case BT_MAP:
331 WriteName(detail::FieldName(metadata));
332 _output.WriteOpen('{');
333 _output.WriteClose('}');
334 break;
335 case BT_INT8:
336 case BT_INT16:
337 case BT_INT32:
338 case BT_INT64:
339 Field(id, metadata, metadata.default_value.int_value);
340 break;
341 case BT_WSTRING:
342 Field(id, metadata, metadata.default_value.wstring_value);
343 break;
344 default:
345 BOOST_ASSERT(false);
346 break;
347 }
348 }
349
350 return false;
351 }
352
353 template <typename T, typename Reader>
354 void Container(const value<T, Reader>& element, uint32_t size) const
355 {
356 _output.WriteOpen('[');
357
358 while (size--)
359 {
360 _output.WriteSeparator();
361 Write(element);
362 }
363
364 _output.WriteClose(']');
365 }
366
367 template <typename Key, typename T, typename Reader>
368 void Container(const value<Key, Reader>& key, const T& value, uint32_t size) const
369 {
370 _output.WriteOpen('[');
371
372 while (size--)
373 {
374 _output.WriteSeparator();
375 Write(key);
376 _output.WriteSeparator();
377 Write(value);
378 }
379
380 _output.WriteClose(']');
381 }
382
383private:
384 void WriteEnd(bool base) const
385 {
386 if (!base)
387 _output.WriteClose('}');
388 }
389
390 template <typename T>
391 void WriteName(const T& name) const
392 {
393 _output.WriteSeparator();
394 _output.WriteName(name);
395 }
396
397 // basic, non-enum type value
398 template <typename T>
399 typename boost::enable_if<is_basic_type<T> >::type
400 Write(const T& value) const
401 {
402 _output.Write(value);
403 }
404
405 // nullable<T> value
406 template <typename T>
407 void Write(const nullable<T>& value) const
408 {
409 if (!value)
410 {
411 _output.WriteNull();
412 }
413 else
414 {
415 _output.WriteOpen('[');
416 Write(value.value());
417 _output.WriteClose(']');
418 }
419 }
420
421 // struct or bonded<T>
422 template <typename T>
423 typename boost::enable_if<is_bond_type<T> >::type
424 Write(const T& value) const
425 {
426 Apply<Protocols>(SerializeTo<Protocols>(_output), value);
427 }
428
429 // 2-tuple
430 template <typename T1, typename T2>
431 void Write(const std::pair<T1, T2>& value) const
432 {
433 Write(value.first);
434 _output.WriteSeparator(is_basic_type<T2>::value ? 2 : 1);
435 Write(value.second);
436 }
437
438 // container value
439 template <typename T>
440 typename boost::enable_if<is_container<T> >::type
441 Write(const T& value) const
442 {
443 _output.WriteOpen('[');
444
445 for (const_enumerator<T> elements(value); elements.more();)
446 {
447 _output.WriteSeparator();
448 Write(elements.next());
449 }
450
451 _output.WriteClose(']');
452 }
453
454 // blob
455 void Write(const blob& value) const
456 {
457 _output.WriteOpen('[');
458
459 for (const char& ch : value)
460 {
461 _output.WriteSeparator();
462 _output.Write(static_cast<int8_t>(ch));
463 }
464
465 _output.WriteClose(']');
466 }
467
468 // serialized value
469 template <typename Reader, typename T>
470 typename boost::enable_if<is_basic_type<T> >::type
471 Write(const value<T, Reader>& value) const
472 {
473 T data;
474
475 value.template Deserialize<Protocols>(data);
476 _output.Write(data);
477 }
478
479 template <typename Reader, typename T>
480 typename boost::disable_if<is_basic_type<T> >::type
481 Write(const value<T, Reader>& value) const
482 {
483 Apply<Protocols>(SerializeTo<Protocols>(_output), value);
484 }
485
486protected:
487 writer_type& _output;
488 mutable uint32_t _level;
489};
490
491
492} // namespace bond
Reader for Simple JSON.
Definition: simple_json_reader.h:28
Writer for Simple JSON.
Definition: simple_json_writer.h:26
SimpleJsonWriter(Buffer &output, bool pretty=false, int indent=4, bool all_fields=true)
Construct from output buffer/stream.
Definition: simple_json_writer.h:36
boost::call_traits< Buffer >::reference GetBuffer()
Access to underlying buffer.
Definition: simple_json_writer.h:49
namespace bond
Definition: apply.h:17
STL namespace.