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