Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.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  {
273  writeKey(fieldInfo.schemaName);
274  }
275 
276  beginObject();
277 }
278 
279 template <typename ALLOC>
282 {
283  endObject();
284 
285  endItem();
286 }
287 
288 template <typename ALLOC>
290  const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
291 {
292  beginItem();
293 
294  if (elementIndex == WALKER_NOT_ELEMENT)
295  {
296  writeKey(fieldInfo.schemaName);
297  }
298 
299  writeValue(value);
300 
301  endItem();
302 }
303 
304 template <typename ALLOC>
306 {
307  if (!m_isFirst)
308  {
309  m_out.write(m_itemSeparator.data(), static_cast<std::streamsize>(m_itemSeparator.size()));
310  }
311 
312  if (m_indent.hasValue())
313  {
314  m_out.put('\n');
315  }
316 
317  writeIndent();
318 }
319 
320 template <typename ALLOC>
321 void BasicJsonWriter<ALLOC>::endItem()
322 {
323  m_isFirst = false;
324 }
325 
326 template <typename ALLOC>
327 void BasicJsonWriter<ALLOC>::beginObject()
328 {
329  m_out.put('{');
330 
331  m_isFirst = true;
332  m_level += 1;
333 }
334 
335 template <typename ALLOC>
336 void BasicJsonWriter<ALLOC>::endObject()
337 {
338  if (m_indent.hasValue())
339  {
340  m_out.put('\n');
341  }
342 
343  m_level -= 1;
344 
345  writeIndent();
346 
347  m_out.put('}');
348 }
349 
350 template <typename ALLOC>
351 void BasicJsonWriter<ALLOC>::beginArray()
352 {
353  m_out.put('[');
354 
355  m_isFirst = true;
356  m_level += 1;
357 }
358 
359 template <typename ALLOC>
360 void BasicJsonWriter<ALLOC>::endArray()
361 {
362  if (m_indent.hasValue())
363  {
364  m_out.put('\n');
365  }
366 
367  m_level -= 1;
368 
369  writeIndent();
370 
371  m_out.put(']');
372 }
373 
374 template <typename ALLOC>
375 void BasicJsonWriter<ALLOC>::writeIndent()
376 {
377  if (m_indent.hasValue())
378  {
379  const auto& indent = m_indent.value();
380  if (!indent.empty())
381  {
382  for (size_t i = 0; i < m_level; ++i)
383  {
384  m_out.write(indent.data(), static_cast<std::streamsize>(indent.size()));
385  }
386  }
387  }
388 }
389 
390 template <typename ALLOC>
391 void BasicJsonWriter<ALLOC>::writeKey(StringView key)
392 {
393  JsonEncoder::encodeString(m_out, key);
394  m_out.write(m_keySeparator.data(), static_cast<std::streamsize>(m_keySeparator.size()));
395  m_out.flush();
396 }
397 
398 template <typename ALLOC>
399 void BasicJsonWriter<ALLOC>::writeValue(const IBasicReflectableConstPtr<ALLOC>& reflectable)
400 {
401  if (!reflectable)
402  {
404  return;
405  }
406 
407  const IBasicTypeInfo<ALLOC>& typeInfo = reflectable->getTypeInfo();
408  switch (typeInfo.getCppType())
409  {
410  case CppType::BOOL:
411  JsonEncoder::encodeBool(m_out, reflectable->getBool());
412  break;
413  case CppType::INT8:
414  case CppType::INT16:
415  case CppType::INT32:
416  case CppType::INT64:
417  JsonEncoder::encodeIntegral(m_out, reflectable->toInt());
418  break;
419  case CppType::UINT8:
420  case CppType::UINT16:
421  case CppType::UINT32:
422  case CppType::UINT64:
423  JsonEncoder::encodeIntegral(m_out, reflectable->toUInt());
424  break;
425  case CppType::FLOAT:
426  JsonEncoder::encodeFloatingPoint(m_out, static_cast<double>(reflectable->getFloat()));
427  break;
428  case CppType::DOUBLE:
429  JsonEncoder::encodeFloatingPoint(m_out, reflectable->getDouble());
430  break;
431  case CppType::BYTES:
432  writeBytes(reflectable->getBytes());
433  break;
434  case CppType::STRING:
435  JsonEncoder::encodeString(m_out, reflectable->getStringView());
436  break;
437  case CppType::BIT_BUFFER:
438  writeBitBuffer(reflectable->getBitBuffer());
439  break;
440  case CppType::ENUM:
441  if (m_enumerableFormat == EnumerableFormat::STRING)
442  {
443  writeStringifiedEnum(reflectable);
444  }
445  else if (TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()))
446  {
447  JsonEncoder::encodeIntegral(m_out, reflectable->toInt());
448  }
449  else
450  {
451  JsonEncoder::encodeIntegral(m_out, reflectable->toUInt());
452  }
453  break;
454  case CppType::BITMASK:
455  if (m_enumerableFormat == EnumerableFormat::STRING)
456  {
457  writeStringifiedBitmask(reflectable);
458  }
459  else
460  {
461  JsonEncoder::encodeIntegral(m_out, reflectable->toUInt());
462  }
463  break;
464  default:
465  throw CppRuntimeException("JsonWriter: Unexpected not-null value of type '")
466  << typeInfo.getSchemaName() << "'!";
467  }
468 
469  m_out.flush();
470 }
471 
472 template <typename ALLOC>
473 void BasicJsonWriter<ALLOC>::writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer)
474 {
475  beginObject();
476  beginItem();
477  writeKey("buffer"_sv);
478  beginArray();
479  Span<const uint8_t> buffer = bitBuffer.getData();
480  for (uint8_t element : buffer)
481  {
482  beginItem();
483  JsonEncoder::encodeIntegral(m_out, element);
484  endItem();
485  }
486  endArray();
487  endItem();
488  beginItem();
489  writeKey("bitSize"_sv);
490  JsonEncoder::encodeIntegral(m_out, bitBuffer.getBitSize());
491  endItem();
492  endObject();
493 }
494 
495 template <typename ALLOC>
496 void BasicJsonWriter<ALLOC>::writeBytes(Span<const uint8_t> value)
497 {
498  beginObject();
499  beginItem();
500  writeKey("buffer"_sv);
501  beginArray();
502  for (uint8_t byte : value)
503  {
504  beginItem();
505  JsonEncoder::encodeIntegral(m_out, byte);
506  endItem();
507  }
508  endArray();
509  endItem();
510  endObject();
511 }
512 
513 template <typename ALLOC>
514 void BasicJsonWriter<ALLOC>::writeStringifiedEnum(const IBasicReflectableConstPtr<ALLOC>& reflectable)
515 {
516  const auto& typeInfo = reflectable->getTypeInfo();
517  const uint64_t enumValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())
518  ? static_cast<uint64_t>(reflectable->toInt())
519  : reflectable->toUInt();
520  for (const auto& itemInfo : typeInfo.getEnumItems())
521  {
522  if (itemInfo.value == enumValue)
523  {
524  // exact match
525  JsonEncoder::encodeString(m_out, itemInfo.schemaName);
526  return;
527  }
528  }
529 
530  // no match
531  string<ALLOC> stringValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())
532  ? toString(reflectable->toInt(), get_allocator())
533  : toString(reflectable->toUInt(), get_allocator());
534  stringValue.append(" /* no match */");
535  JsonEncoder::encodeString(m_out, stringValue);
536 }
537 
538 template <typename ALLOC>
539 void BasicJsonWriter<ALLOC>::writeStringifiedBitmask(const IBasicReflectableConstPtr<ALLOC>& reflectable)
540 {
541  string<ALLOC> stringValue(get_allocator());
542  const auto& typeInfo = reflectable->getTypeInfo();
543  const uint64_t bitmaskValue = reflectable->toUInt();
544  uint64_t valueCheck = 0;
545  for (const auto& itemInfo : typeInfo.getBitmaskValues())
546  {
547  if ((itemInfo.value != 0 && (bitmaskValue & itemInfo.value) == itemInfo.value) ||
548  (itemInfo.value == 0 && bitmaskValue == 0))
549  {
550  valueCheck |= itemInfo.value;
551  if (!stringValue.empty())
552  {
553  stringValue += " | ";
554  }
555  stringValue += toString(itemInfo.schemaName, get_allocator());
556  }
557  }
558 
559  if (stringValue.empty())
560  {
561  // no match
562  stringValue.append(toString(bitmaskValue, get_allocator()));
563  stringValue.append(" /* no match */");
564  }
565  else if (bitmaskValue != valueCheck)
566  {
567  // partial match
568  stringValue =
569  toString(bitmaskValue, get_allocator())
570  .append(" /* partial match: ")
571  .append(stringValue)
572  .append(" */");
573  }
574  // else exact match
575 
576  JsonEncoder::encodeString(m_out, stringValue);
577 }
578 
579 } // namespace zserio
580 
581 #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:289
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:280
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: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:65
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:534
detail::inplace_optional_holder< T > InplaceOptionalHolder
StringView schemaName
Definition: ITypeInfo.h:379
static bool isSigned(SchemaType schemaType)