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