Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.0
JsonWriter.h
Go to the documentation of this file.
1 #ifndef ZSERIO_JSON_WRITER_H_INC
2 #define ZSERIO_JSON_WRITER_H_INC
3 
4 #include <ostream>
5 
7 #include "zserio/IWalkObserver.h"
8 #include "zserio/JsonEncoder.h"
10 #include "zserio/TypeInfoUtil.h"
11 
12 namespace zserio
13 {
14 
18 template <typename ALLOC = std::allocator<uint8_t>>
19 class BasicJsonWriter : public IBasicWalkObserver<ALLOC>, public AllocatorHolder<ALLOC>
20 {
21 public:
23 
27  static constexpr const char* DEFAULT_ITEM_SEPARATOR = ", ";
28 
32  static constexpr const char* DEFAULT_ITEM_SEPARATOR_WITH_INDENT = ",";
33 
37  static constexpr const char* DEFAULT_KEY_SEPARATOR = ": ";
38 
42  enum class EnumerableFormat
43  {
45  NUMBER,
62  STRING
63  };
68 
75  explicit BasicJsonWriter(std::ostream& out, const ALLOC& allocator = ALLOC());
76 
84  BasicJsonWriter(std::ostream& out, uint8_t indent, const ALLOC& allocator = ALLOC());
85 
93  BasicJsonWriter(std::ostream& out, const string<ALLOC>& indent, const ALLOC& allocator = ALLOC());
94 
98  ~BasicJsonWriter() override = default;
99 
104  BasicJsonWriter(const BasicJsonWriter& other) = delete;
105  BasicJsonWriter& operator=(const BasicJsonWriter& other) = delete;
106 
107  BasicJsonWriter(BasicJsonWriter&& other) = delete;
120  void setItemSeparator(const string<ALLOC>& itemSeparator);
121 
129  void setKeySeparator(const string<ALLOC>& keySeparator);
130 
136  void setEnumerableFormat(EnumerableFormat enumerableFormat);
137 
138  void beginRoot(const IBasicReflectableConstPtr<ALLOC>& compound) override;
139  void endRoot(const IBasicReflectableConstPtr<ALLOC>& compound) override;
140 
141  void beginArray(
142  const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
143  void endArray(
144  const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
145 
146  void beginCompound(const IBasicReflectableConstPtr<ALLOC>& compound, const BasicFieldInfo<ALLOC>& fieldInfo,
147  size_t elementIndex) override;
148  void endCompound(const IBasicReflectableConstPtr<ALLOC>& compound, const BasicFieldInfo<ALLOC>& fieldInfo,
149  size_t elementIndex) override;
150 
151  void visitValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
152  size_t elementIndex) override;
153 
154 private:
155  BasicJsonWriter(std::ostream& out, InplaceOptionalHolder<string<ALLOC>>&& optionalIndent,
156  const ALLOC& allocator = ALLOC());
157 
158  void beginItem();
159  void endItem();
160  void beginObject();
161  void endObject();
162  void beginArray();
163  void endArray();
164 
165  void writeIndent();
166  void writeKey(StringView key);
167  void writeValue(const IBasicReflectableConstPtr<ALLOC>& reflectable);
168  void writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer);
169  void writeBytes(Span<const uint8_t> value);
170  void writeStringifiedEnum(const IBasicReflectableConstPtr<ALLOC>& reflectable);
171  void writeStringifiedBitmask(const IBasicReflectableConstPtr<ALLOC>& reflectable);
172 
173  std::ostream& m_out;
175  string<ALLOC> m_itemSeparator;
176  string<ALLOC> m_keySeparator;
177  EnumerableFormat m_enumerableFormat = DEFAULT_ENUMERABLE_FORMAT;
178 
179  bool m_isFirst = true;
180  size_t m_level = 0;
181 };
182 
188 template <typename ALLOC>
189 BasicJsonWriter<ALLOC>::BasicJsonWriter(std::ostream& out, const ALLOC& allocator) :
190  BasicJsonWriter(out, NullOpt, allocator)
191 {}
192 
193 template <typename ALLOC>
194 BasicJsonWriter<ALLOC>::BasicJsonWriter(std::ostream& out, uint8_t indent, const ALLOC& allocator) :
195  BasicJsonWriter(out, string<ALLOC>(indent, ' ', allocator), allocator)
196 {}
197 
198 template <typename ALLOC>
200  std::ostream& out, const string<ALLOC>& indent, const ALLOC& allocator) :
201  BasicJsonWriter(out, InplaceOptionalHolder<string<ALLOC>>(indent), allocator)
202 {}
203 
204 template <typename ALLOC>
206  std::ostream& out, InplaceOptionalHolder<string<ALLOC>>&& optionalIndent, const ALLOC& allocator) :
207  AllocatorHolder<ALLOC>(allocator),
208  m_out(out),
209  m_indent(optionalIndent),
210  m_itemSeparator(
211  m_indent.hasValue() ? DEFAULT_ITEM_SEPARATOR_WITH_INDENT : DEFAULT_ITEM_SEPARATOR, allocator),
212  m_keySeparator(DEFAULT_KEY_SEPARATOR, allocator)
213 {}
214 
215 template <typename ALLOC>
217 {
218  m_itemSeparator = itemSeparator;
219 }
220 
221 template <typename ALLOC>
223 {
224  m_keySeparator = keySeparator;
225 }
226 
227 template <typename ALLOC>
229 {
230  m_enumerableFormat = enumerableFormat;
231 }
232 
233 template <typename ALLOC>
235 {
236  beginObject();
237 }
238 
239 template <typename ALLOC>
241 {
242  endObject();
243  m_out.flush();
244 }
245 
246 template <typename ALLOC>
249 {
250  beginItem();
251 
252  writeKey(fieldInfo.schemaName);
253 
254  beginArray();
255 }
256 
257 template <typename ALLOC>
259 {
260  endArray();
261 
262  endItem();
263 }
264 
265 template <typename ALLOC>
267  const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
268 {
269  beginItem();
270 
271  if (elementIndex == WALKER_NOT_ELEMENT)
272  writeKey(fieldInfo.schemaName);
273 
274  beginObject();
275 }
276 
277 template <typename ALLOC>
280 {
281  endObject();
282 
283  endItem();
284 }
285 
286 template <typename ALLOC>
288  const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
289 {
290  beginItem();
291 
292  if (elementIndex == WALKER_NOT_ELEMENT)
293  writeKey(fieldInfo.schemaName);
294 
295  writeValue(value);
296 
297  endItem();
298 }
299 
300 template <typename ALLOC>
302 {
303  if (!m_isFirst)
304  m_out.write(m_itemSeparator.data(), static_cast<std::streamsize>(m_itemSeparator.size()));
305 
306  if (m_indent.hasValue())
307  m_out.put('\n');
308 
309  writeIndent();
310 }
311 
312 template <typename ALLOC>
313 void BasicJsonWriter<ALLOC>::endItem()
314 {
315  m_isFirst = false;
316 }
317 
318 template <typename ALLOC>
319 void BasicJsonWriter<ALLOC>::beginObject()
320 {
321  m_out.put('{');
322 
323  m_isFirst = true;
324  m_level += 1;
325 }
326 
327 template <typename ALLOC>
328 void BasicJsonWriter<ALLOC>::endObject()
329 {
330  if (m_indent.hasValue())
331  m_out.put('\n');
332 
333  m_level -= 1;
334 
335  writeIndent();
336 
337  m_out.put('}');
338 }
339 
340 template <typename ALLOC>
341 void BasicJsonWriter<ALLOC>::beginArray()
342 {
343  m_out.put('[');
344 
345  m_isFirst = true;
346  m_level += 1;
347 }
348 
349 template <typename ALLOC>
350 void BasicJsonWriter<ALLOC>::endArray()
351 {
352  if (m_indent.hasValue())
353  m_out.put('\n');
354 
355  m_level -= 1;
356 
357  writeIndent();
358 
359  m_out.put(']');
360 }
361 
362 template <typename ALLOC>
363 void BasicJsonWriter<ALLOC>::writeIndent()
364 {
365  if (m_indent.hasValue())
366  {
367  const auto& indent = m_indent.value();
368  if (!indent.empty())
369  {
370  for (size_t i = 0; i < m_level; ++i)
371  m_out.write(indent.data(), static_cast<std::streamsize>(indent.size()));
372  }
373  }
374 }
375 
376 template <typename ALLOC>
377 void BasicJsonWriter<ALLOC>::writeKey(StringView key)
378 {
379  JsonEncoder::encodeString(m_out, key);
380  m_out.write(m_keySeparator.data(), static_cast<std::streamsize>(m_keySeparator.size()));
381  m_out.flush();
382 }
383 
384 template <typename ALLOC>
385 void BasicJsonWriter<ALLOC>::writeValue(const IBasicReflectableConstPtr<ALLOC>& reflectable)
386 {
387  if (!reflectable)
388  {
390  return;
391  }
392 
393  const IBasicTypeInfo<ALLOC>& typeInfo = reflectable->getTypeInfo();
394  switch (typeInfo.getCppType())
395  {
396  case CppType::BOOL:
397  JsonEncoder::encodeBool(m_out, reflectable->getBool());
398  break;
399  case CppType::INT8:
400  case CppType::INT16:
401  case CppType::INT32:
402  case CppType::INT64:
403  JsonEncoder::encodeIntegral(m_out, reflectable->toInt());
404  break;
405  case CppType::UINT8:
406  case CppType::UINT16:
407  case CppType::UINT32:
408  case CppType::UINT64:
409  JsonEncoder::encodeIntegral(m_out, reflectable->toUInt());
410  break;
411  case CppType::FLOAT:
412  JsonEncoder::encodeFloatingPoint(m_out, static_cast<double>(reflectable->getFloat()));
413  break;
414  case CppType::DOUBLE:
415  JsonEncoder::encodeFloatingPoint(m_out, reflectable->getDouble());
416  break;
417  case CppType::BYTES:
418  writeBytes(reflectable->getBytes());
419  break;
420  case CppType::STRING:
421  JsonEncoder::encodeString(m_out, reflectable->getStringView());
422  break;
423  case CppType::BIT_BUFFER:
424  writeBitBuffer(reflectable->getBitBuffer());
425  break;
426  case CppType::ENUM:
427  if (m_enumerableFormat == EnumerableFormat::STRING)
428  writeStringifiedEnum(reflectable);
429  else if (TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()))
430  JsonEncoder::encodeIntegral(m_out, reflectable->toInt());
431  else
432  JsonEncoder::encodeIntegral(m_out, reflectable->toUInt());
433  break;
434  case CppType::BITMASK:
435  if (m_enumerableFormat == EnumerableFormat::STRING)
436  writeStringifiedBitmask(reflectable);
437  else
438  JsonEncoder::encodeIntegral(m_out, reflectable->toUInt());
439  break;
440  default:
441  throw CppRuntimeException("JsonWriter: Unexpected not-null value of type '")
442  << typeInfo.getSchemaName() << "'!";
443  }
444 
445  m_out.flush();
446 }
447 
448 template <typename ALLOC>
449 void BasicJsonWriter<ALLOC>::writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer)
450 {
451  beginObject();
452  beginItem();
453  writeKey("buffer"_sv);
454  beginArray();
455  Span<const uint8_t> buffer = bitBuffer.getData();
456  for (uint8_t element : buffer)
457  {
458  beginItem();
459  JsonEncoder::encodeIntegral(m_out, element);
460  endItem();
461  }
462  endArray();
463  endItem();
464  beginItem();
465  writeKey("bitSize"_sv);
466  JsonEncoder::encodeIntegral(m_out, bitBuffer.getBitSize());
467  endItem();
468  endObject();
469 }
470 
471 template <typename ALLOC>
472 void BasicJsonWriter<ALLOC>::writeBytes(Span<const uint8_t> value)
473 {
474  beginObject();
475  beginItem();
476  writeKey("buffer"_sv);
477  beginArray();
478  for (uint8_t byte : value)
479  {
480  beginItem();
481  JsonEncoder::encodeIntegral(m_out, byte);
482  endItem();
483  }
484  endArray();
485  endItem();
486  endObject();
487 }
488 
489 template <typename ALLOC>
490 void BasicJsonWriter<ALLOC>::writeStringifiedEnum(const IBasicReflectableConstPtr<ALLOC>& reflectable)
491 {
492  const auto& typeInfo = reflectable->getTypeInfo();
493  const uint64_t enumValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())
494  ? static_cast<uint64_t>(reflectable->toInt())
495  : reflectable->toUInt();
496  for (const auto& itemInfo : typeInfo.getEnumItems())
497  {
498  if (itemInfo.value == enumValue)
499  {
500  // exact match
501  JsonEncoder::encodeString(m_out, itemInfo.schemaName);
502  return;
503  }
504  }
505 
506  // no match
507  string<ALLOC> stringValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())
508  ? toString(reflectable->toInt(), get_allocator())
509  : toString(reflectable->toUInt(), get_allocator());
510  stringValue.append(" /* no match */");
511  JsonEncoder::encodeString(m_out, stringValue);
512 }
513 
514 template <typename ALLOC>
515 void BasicJsonWriter<ALLOC>::writeStringifiedBitmask(const IBasicReflectableConstPtr<ALLOC>& reflectable)
516 {
517  string<ALLOC> stringValue(get_allocator());
518  const auto& typeInfo = reflectable->getTypeInfo();
519  const uint64_t bitmaskValue = reflectable->toUInt();
520  uint64_t valueCheck = 0;
521  for (const auto& itemInfo : typeInfo.getBitmaskValues())
522  {
523  if ((itemInfo.value != 0 && (bitmaskValue & itemInfo.value) == itemInfo.value) ||
524  (itemInfo.value == 0 && bitmaskValue == 0))
525  {
526  valueCheck |= itemInfo.value;
527  if (!stringValue.empty())
528  stringValue += " | ";
529  stringValue += toString(itemInfo.schemaName, get_allocator());
530  }
531  }
532 
533  if (stringValue.empty())
534  {
535  // no match
536  stringValue.append(toString(bitmaskValue, get_allocator()));
537  stringValue.append(" /* no match */");
538  }
539  else if (bitmaskValue != valueCheck)
540  {
541  // partial match
542  stringValue =
543  toString(bitmaskValue, get_allocator())
544  .append(" /* partial match: ")
545  .append(stringValue)
546  .append(" */");
547  }
548  // else exact match
549 
550  JsonEncoder::encodeString(m_out, stringValue);
551 }
552 
553 } // namespace zserio
554 
555 #endif // ZSERIO_JSON_WRITER_H_INC
BasicJsonWriter(std::ostream &out, const ALLOC &allocator=ALLOC())
Definition: JsonWriter.h:189
static constexpr const char * DEFAULT_ITEM_SEPARATOR_WITH_INDENT
Definition: JsonWriter.h:32
void endRoot(const IBasicReflectableConstPtr< ALLOC > &compound) override
Definition: JsonWriter.h:240
BasicJsonWriter & operator=(const BasicJsonWriter &other)=delete
void visitValue(const IBasicReflectableConstPtr< ALLOC > &value, const BasicFieldInfo< ALLOC > &fieldInfo, size_t elementIndex) override
Definition: JsonWriter.h:287
void beginCompound(const IBasicReflectableConstPtr< ALLOC > &compound, const BasicFieldInfo< ALLOC > &fieldInfo, size_t elementIndex) override
Definition: JsonWriter.h:266
static constexpr const char * DEFAULT_KEY_SEPARATOR
Definition: JsonWriter.h:37
BasicJsonWriter(BasicJsonWriter &&other)=delete
void endArray(const IBasicReflectableConstPtr< ALLOC > &array, const BasicFieldInfo< ALLOC > &fieldInfo) override
Definition: JsonWriter.h:258
void setItemSeparator(const string< ALLOC > &itemSeparator)
Definition: JsonWriter.h:216
~BasicJsonWriter() override=default
BasicJsonWriter(const BasicJsonWriter &other)=delete
void setEnumerableFormat(EnumerableFormat enumerableFormat)
Definition: JsonWriter.h:228
BasicJsonWriter & operator=(BasicJsonWriter &&other)=delete
static constexpr const char * DEFAULT_ITEM_SEPARATOR
Definition: JsonWriter.h:27
void setKeySeparator(const string< ALLOC > &keySeparator)
Definition: JsonWriter.h:222
void endCompound(const IBasicReflectableConstPtr< ALLOC > &compound, const BasicFieldInfo< ALLOC > &fieldInfo, size_t elementIndex) override
Definition: JsonWriter.h:278
static constexpr EnumerableFormat DEFAULT_ENUMERABLE_FORMAT
Definition: JsonWriter.h:67
void beginRoot(const IBasicReflectableConstPtr< ALLOC > &compound) override
Definition: JsonWriter.h:234
void beginArray(const IBasicReflectableConstPtr< ALLOC > &array, const BasicFieldInfo< ALLOC > &fieldInfo) override
Definition: JsonWriter.h:247
static void encodeFloatingPoint(std::ostream &stream, double value)
Definition: JsonEncoder.cpp:20
static void encodeNull(std::ostream &stream)
Definition: JsonEncoder.cpp:10
static void encodeBool(std::ostream &stream, bool value)
Definition: JsonEncoder.cpp:15
static void encodeString(std::ostream &stream, StringView value)
Definition: JsonEncoder.cpp:48
static void encodeIntegral(std::ostream &stream, T value)
Definition: JsonEncoder.h:65
constexpr NullOptType NullOpt
BasicStringView< char, std::char_traits< char > > StringView
Definition: StringView.h:936
std::basic_string< char, std::char_traits< char >, RebindAlloc< ALLOC, char > > string
Definition: String.h:17
string< ALLOC > toString(T value, const ALLOC &allocator=ALLOC())
typename IBasicReflectable< ALLOC >::ConstPtr IBasicReflectableConstPtr
Definition: IReflectable.h:519
detail::inplace_optional_holder< T > InplaceOptionalHolder
StringView schemaName
Definition: ITypeInfo.h:379
static bool isSigned(SchemaType schemaType)