Zserio C++17 runtime library 1.3.0
Built for Zserio 2.20.0
Loading...
Searching...
No Matches
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#include <string_view>
6
10#include "zserio/Optional.h"
11#include "zserio/String.h"
12#include "zserio/TypeInfoUtil.h"
13
14namespace zserio
15{
16using namespace std::literals::string_view_literals;
17
21template <typename ALLOC = std::allocator<uint8_t>>
22class BasicJsonWriter : public IBasicWalkObserver<ALLOC>, public AllocatorHolder<ALLOC>
23{
24public:
26
30 static constexpr const char* DEFAULT_ITEM_SEPARATOR = ", ";
31
35 static constexpr const char* DEFAULT_ITEM_SEPARATOR_WITH_INDENT = ",";
36
40 static constexpr const char* DEFAULT_KEY_SEPARATOR = ": ";
41
46 {
48 NUMBER,
65 STRING
66 };
71
78 explicit BasicJsonWriter(std::ostream& out, const ALLOC& allocator = ALLOC());
79
87 BasicJsonWriter(std::ostream& out, uint8_t indent, const ALLOC& allocator = ALLOC());
88
97 const ALLOC& allocator = ALLOC());
98
102 ~BasicJsonWriter() override = default;
103
110
125
134
141
144
145 void beginArray(
147 void endArray(
149
151 const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
153 const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
154
156 size_t elementIndex) override;
157
158private:
160 const ALLOC& allocator = ALLOC());
161
162 void beginItem();
163 void endItem();
164 void beginObject();
165 void endObject();
166 void beginArray();
167 void endArray();
168
169 void writeIndent();
170 void writeKey(std::string_view key);
172 void writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer);
173 void writeBytes(Span<const uint8_t> value);
174 void writeStringifiedEnum(const IBasicReflectableDataConstPtr<ALLOC>& reflectable);
175 void writeStringifiedBitmask(const IBasicReflectableDataConstPtr<ALLOC>& reflectable);
176
177 std::ostream& m_out;
181 EnumerableFormat m_enumerableFormat = DEFAULT_ENUMERABLE_FORMAT;
182
183 bool m_isFirst = true;
184 size_t m_level = 0;
185};
186
192template <typename ALLOC>
196
197template <typename ALLOC>
201
202template <typename ALLOC>
207
208template <typename ALLOC>
212 m_out(out),
213 m_indent(optionalIndent),
214 m_itemSeparator(
215 m_indent.has_value() ? DEFAULT_ITEM_SEPARATOR_WITH_INDENT : DEFAULT_ITEM_SEPARATOR, allocator),
216 m_keySeparator(DEFAULT_KEY_SEPARATOR, allocator)
217{}
218
219template <typename ALLOC>
224
225template <typename ALLOC>
230
231template <typename ALLOC>
236
237template <typename ALLOC>
242
243template <typename ALLOC>
245{
246 endObject();
247 m_out.flush();
248}
249
250template <typename ALLOC>
253{
254 beginItem();
255
256 writeKey(fieldInfo.schemaName);
257
258 beginArray();
259}
260
261template <typename ALLOC>
263{
264 endArray();
265
266 endItem();
267}
268
269template <typename ALLOC>
272{
273 beginItem();
274
275 if (elementIndex == WALKER_NOT_ELEMENT)
276 {
277 writeKey(fieldInfo.schemaName);
278 }
279
280 beginObject();
281}
282
283template <typename ALLOC>
286{
287 endObject();
288
289 endItem();
290}
291
292template <typename ALLOC>
295{
296 beginItem();
297
298 if (elementIndex == WALKER_NOT_ELEMENT)
299 {
300 writeKey(fieldInfo.schemaName);
301 }
302
303 writeValue(value);
304
305 endItem();
306}
307
308template <typename ALLOC>
310{
311 if (!m_isFirst)
312 {
313 m_out.write(m_itemSeparator.data(), static_cast<std::streamsize>(m_itemSeparator.size()));
314 }
315
316 if (m_indent.has_value())
317 {
318 m_out.put('\n');
319 }
320
321 writeIndent();
322}
323
324template <typename ALLOC>
325void BasicJsonWriter<ALLOC>::endItem()
326{
327 m_isFirst = false;
328}
329
330template <typename ALLOC>
331void BasicJsonWriter<ALLOC>::beginObject()
332{
333 m_out.put('{');
334
335 m_isFirst = true;
336 m_level += 1;
337}
338
339template <typename ALLOC>
340void BasicJsonWriter<ALLOC>::endObject()
341{
342 if (m_indent.has_value())
343 {
344 m_out.put('\n');
345 }
346
347 m_level -= 1;
348
349 writeIndent();
350
351 m_out.put('}');
352}
353
354template <typename ALLOC>
355void BasicJsonWriter<ALLOC>::beginArray()
356{
357 m_out.put('[');
358
359 m_isFirst = true;
360 m_level += 1;
361}
362
363template <typename ALLOC>
364void BasicJsonWriter<ALLOC>::endArray()
365{
366 if (m_indent.has_value())
367 {
368 m_out.put('\n');
369 }
370
371 m_level -= 1;
372
373 writeIndent();
374
375 m_out.put(']');
376}
377
378template <typename ALLOC>
379void BasicJsonWriter<ALLOC>::writeIndent()
380{
381 if (m_indent.has_value())
382 {
383 const auto& indent = m_indent.value();
384 if (!indent.empty())
385 {
386 for (size_t i = 0; i < m_level; ++i)
387 {
388 m_out.write(indent.data(), static_cast<std::streamsize>(indent.size()));
389 }
390 }
391 }
392}
393
394template <typename ALLOC>
395void BasicJsonWriter<ALLOC>::writeKey(std::string_view key)
396{
397 JsonEncoder::encodeString(m_out, key);
398 m_out.write(m_keySeparator.data(), static_cast<std::streamsize>(m_keySeparator.size()));
399 m_out.flush();
400}
401
402template <typename ALLOC>
403void BasicJsonWriter<ALLOC>::writeValue(const IBasicReflectableDataConstPtr<ALLOC>& reflectable)
404{
405 if (!reflectable)
406 {
408 return;
409 }
410
411 const IBasicTypeInfo<ALLOC>& typeInfo = reflectable->getTypeInfo();
412 switch (typeInfo.getCppType())
413 {
414 case CppType::BOOL:
415 JsonEncoder::encodeBool(m_out, reflectable->getBool());
416 break;
417 case CppType::INT8:
418 case CppType::INT16:
419 case CppType::INT32:
420 case CppType::INT64:
422 break;
423 case CppType::UINT8:
424 case CppType::UINT16:
425 case CppType::UINT32:
426 case CppType::UINT64:
428 break;
429 case CppType::FLOAT:
430 JsonEncoder::encodeFloatingPoint(m_out, static_cast<double>(reflectable->getFloat()));
431 break;
432 case CppType::DOUBLE:
434 break;
435 case CppType::BYTES:
436 writeBytes(reflectable->getBytes());
437 break;
438 case CppType::STRING:
439 JsonEncoder::encodeString(m_out, reflectable->getStringView());
440 break;
442 writeBitBuffer(reflectable->getBitBuffer());
443 break;
444 case CppType::ENUM:
445 if (m_enumerableFormat == EnumerableFormat::STRING)
446 {
447 writeStringifiedEnum(reflectable);
448 }
449 else if (TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()))
450 {
452 }
453 else
454 {
456 }
457 break;
458 case CppType::BITMASK:
459 if (m_enumerableFormat == EnumerableFormat::STRING)
460 {
461 writeStringifiedBitmask(reflectable);
462 }
463 else
464 {
466 }
467 break;
468 default:
469 throw CppRuntimeException("JsonWriter: Unexpected not-null value of type '")
470 << typeInfo.getSchemaName() << "'!";
471 }
472
473 m_out.flush();
474}
475
476template <typename ALLOC>
477void BasicJsonWriter<ALLOC>::writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer)
478{
479 beginObject();
480 beginItem();
481 writeKey("buffer"sv);
482 beginArray();
483 Span<const uint8_t> buffer = bitBuffer.getData();
484 for (uint8_t element : buffer)
485 {
486 beginItem();
487 JsonEncoder::encodeIntegral(m_out, element);
488 endItem();
489 }
490 endArray();
491 endItem();
492 beginItem();
493 writeKey("bitSize"sv);
494 JsonEncoder::encodeIntegral(m_out, bitBuffer.getBitSize());
495 endItem();
496 endObject();
497}
498
499template <typename ALLOC>
500void BasicJsonWriter<ALLOC>::writeBytes(Span<const uint8_t> value)
501{
502 beginObject();
503 beginItem();
504 writeKey("buffer"sv);
505 beginArray();
506 for (uint8_t byte : value)
507 {
508 beginItem();
509 JsonEncoder::encodeIntegral(m_out, byte);
510 endItem();
511 }
512 endArray();
513 endItem();
514 endObject();
515}
516
517template <typename ALLOC>
518void BasicJsonWriter<ALLOC>::writeStringifiedEnum(const IBasicReflectableDataConstPtr<ALLOC>& reflectable)
519{
520 const auto& typeInfo = reflectable->getTypeInfo();
521 const uint64_t enumValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())
522 ? static_cast<uint64_t>(reflectable->toInt())
523 : reflectable->toUInt();
524 for (const auto& itemInfo : typeInfo.getEnumItems())
525 {
526 if (itemInfo.value == enumValue)
527 {
528 // exact match
529 JsonEncoder::encodeString(m_out, itemInfo.schemaName);
530 return;
531 }
532 }
533
534 // no match
535 BasicString<RebindAlloc<ALLOC, char>> stringValue =
536 TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())
537 ? toString(reflectable->toInt(), get_allocator())
538 : toString(reflectable->toUInt(), get_allocator());
539 stringValue.append(" /* no match */");
540 JsonEncoder::encodeString(m_out, stringValue);
541}
542
543template <typename ALLOC>
544void BasicJsonWriter<ALLOC>::writeStringifiedBitmask(const IBasicReflectableDataConstPtr<ALLOC>& reflectable)
545{
546 BasicString<RebindAlloc<ALLOC, char>> stringValue(get_allocator());
547 const auto& typeInfo = reflectable->getTypeInfo();
548 const uint64_t bitmaskValue = reflectable->toUInt();
549 uint64_t valueCheck = 0;
550 for (const auto& itemInfo : typeInfo.getBitmaskValues())
551 {
552 if ((itemInfo.value != 0 && (bitmaskValue & itemInfo.value) == itemInfo.value) ||
553 (itemInfo.value == 0 && bitmaskValue == 0))
554 {
555 valueCheck |= itemInfo.value;
556 if (!stringValue.empty())
557 {
558 stringValue += " | ";
559 }
560 stringValue += toString(itemInfo.schemaName, get_allocator());
561 }
562 }
563
564 if (stringValue.empty())
565 {
566 // no match
567 stringValue.append(toString(bitmaskValue, get_allocator()));
568 stringValue.append(" /* no match */");
569 }
570 else if (bitmaskValue != valueCheck)
571 {
572 // partial match
573 stringValue =
574 toString(bitmaskValue, get_allocator())
575 .append(" /* partial match: ")
576 .append(stringValue)
577 .append(" */");
578 }
579 // else exact match
580
581 JsonEncoder::encodeString(m_out, stringValue);
582}
583
584} // namespace zserio
585
586#endif // ZSERIO_JSON_WRITER_H_INC
allocator_type get_allocator() const
void beginArray(const IBasicReflectableDataConstPtr< ALLOC > &array, const BasicFieldInfo< ALLOC > &fieldInfo) override
Definition JsonWriter.h:251
void setKeySeparator(const BasicString< RebindAlloc< ALLOC, char > > &keySeparator)
Definition JsonWriter.h:226
BasicJsonWriter(std::ostream &out, const ALLOC &allocator=ALLOC())
Definition JsonWriter.h:193
static constexpr const char * DEFAULT_ITEM_SEPARATOR_WITH_INDENT
Definition JsonWriter.h:35
void endRoot(const IBasicReflectableDataConstPtr< ALLOC > &compound) override
Definition JsonWriter.h:244
BasicJsonWriter & operator=(BasicJsonWriter &&other)=delete
static constexpr const char * DEFAULT_KEY_SEPARATOR
Definition JsonWriter.h:40
BasicJsonWriter(BasicJsonWriter &&other)=delete
void visitValue(const IBasicReflectableDataConstPtr< ALLOC > &value, const BasicFieldInfo< ALLOC > &fieldInfo, size_t elementIndex) override
Definition JsonWriter.h:293
BasicJsonWriter & operator=(const BasicJsonWriter &other)=delete
void endArray(const IBasicReflectableDataConstPtr< ALLOC > &array, const BasicFieldInfo< ALLOC > &fieldInfo) override
Definition JsonWriter.h:262
void endCompound(const IBasicReflectableDataConstPtr< ALLOC > &compound, const BasicFieldInfo< ALLOC > &fieldInfo, size_t elementIndex) override
Definition JsonWriter.h:284
~BasicJsonWriter() override=default
BasicJsonWriter(const BasicJsonWriter &other)=delete
void setEnumerableFormat(EnumerableFormat enumerableFormat)
Definition JsonWriter.h:232
void beginCompound(const IBasicReflectableDataConstPtr< ALLOC > &compound, const BasicFieldInfo< ALLOC > &fieldInfo, size_t elementIndex) override
Definition JsonWriter.h:270
void beginRoot(const IBasicReflectableDataConstPtr< ALLOC > &compound) override
Definition JsonWriter.h:238
static constexpr const char * DEFAULT_ITEM_SEPARATOR
Definition JsonWriter.h:30
void setItemSeparator(const BasicString< RebindAlloc< ALLOC, char > > &itemSeparator)
Definition JsonWriter.h:220
static constexpr EnumerableFormat DEFAULT_ENUMERABLE_FORMAT
Definition JsonWriter.h:70
static void encodeFloatingPoint(std::ostream &stream, double value)
static void encodeNull(std::ostream &stream)
static void encodeBool(std::ostream &stream, bool value)
static void encodeIntegral(std::ostream &stream, T value)
Definition JsonEncoder.h:65
static void encodeString(std::ostream &stream, std::string_view value)
const IBasicTypeInfo< ALLOC > & typeInfo()
Definition ITypeInfo.h:668
std::basic_string< char, std::char_traits< char >, ALLOC > BasicString
Definition String.h:17
typename std::allocator_traits< ALLOC >::template rebind_alloc< T > RebindAlloc
Definition RebindAlloc.h:10
BasicString< RebindAlloc< ALLOC, char > > toString(T value, const ALLOC &allocator=ALLOC())
IBasicReflectableDataConstPtr< ALLOC > reflectable(const T &value, const ALLOC &allocator=ALLOC())
static bool isSigned(SchemaType schemaType)