Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef ZSERIO_JSON_WRITER_H_INC |
2 | | #define ZSERIO_JSON_WRITER_H_INC |
3 | | |
4 | | #include <ostream> |
5 | | |
6 | | #include "zserio/AllocatorHolder.h" |
7 | | #include "zserio/IWalkObserver.h" |
8 | | #include "zserio/JsonEncoder.h" |
9 | | #include "zserio/OptionalHolder.h" |
10 | | #include "zserio/TypeInfoUtil.h" |
11 | | |
12 | | namespace zserio |
13 | | { |
14 | | |
15 | | /** |
16 | | * Walker observer which dumps zserio objects to JSON format. |
17 | | */ |
18 | | template <typename ALLOC = std::allocator<uint8_t>> |
19 | | class BasicJsonWriter : public IBasicWalkObserver<ALLOC>, public AllocatorHolder<ALLOC> |
20 | | { |
21 | | public: |
22 | | using AllocatorHolder<ALLOC>::get_allocator; |
23 | | |
24 | | /** |
25 | | * Default item separator used when indent is not set. |
26 | | */ |
27 | | static constexpr const char* DEFAULT_ITEM_SEPARATOR = ", "; |
28 | | |
29 | | /** |
30 | | * Default item separator used when indent is set. |
31 | | */ |
32 | | static constexpr const char* DEFAULT_ITEM_SEPARATOR_WITH_INDENT = ","; |
33 | | |
34 | | /** |
35 | | * Default key separator. |
36 | | */ |
37 | | static constexpr const char* DEFAULT_KEY_SEPARATOR = ": "; |
38 | | |
39 | | /** |
40 | | * Configuration for writing of enumerable types. |
41 | | */ |
42 | | enum class EnumerableFormat |
43 | | { |
44 | | /** Print as JSON integral value. */ |
45 | | NUMBER, |
46 | | /** |
47 | | * Print as JSON string according to the following rules: |
48 | | * |
49 | | * 1. Enums |
50 | | * * when an exact match with an enumerable item is found, the item name is used - e.g. "FIRST", |
51 | | * * when no exact match is found, it's an invalid value, the integral value is converted to string |
52 | | * and an appropriate comment is included - e.g. \"10 /<span>*</span> no match <span>*</span>/\". |
53 | | * |
54 | | * 2. Bitmasks |
55 | | * * when an exact mach with or-ed bitmask values is found, it's used - e.g. "READ | WRITE", |
56 | | * * when no exact match is found, but some or-ed values match, the integral value is converted |
57 | | * to string and the or-ed values are included in a comment - e.g. |
58 | | * \"127 /<span>*</span> READ | CREATE <span>*</span>/\", |
59 | | * * when no match is found at all, the integral value is converted to string and an appropriate |
60 | | * comment is included - e.g. \"13 /<span>*</span> no match <span>*</span>/\". |
61 | | */ |
62 | | STRING |
63 | | }; |
64 | | /** |
65 | | * Default configuration for enumerable types. |
66 | | */ |
67 | | static constexpr EnumerableFormat DEFAULT_ENUMERABLE_FORMAT = EnumerableFormat::STRING; |
68 | | |
69 | | /** |
70 | | * Constructor. |
71 | | * |
72 | | * \param out Stream to use for writing. |
73 | | * \param allocator Allocator to use. |
74 | | */ |
75 | | explicit BasicJsonWriter(std::ostream& out, const ALLOC& allocator = ALLOC()); |
76 | | |
77 | | /** |
78 | | * Constructor. |
79 | | * |
80 | | * \param out Stream to use for writing. |
81 | | * \param indent Indent as a number of ' ' to be used for indentation. |
82 | | * \param allocator Allocator to use. |
83 | | */ |
84 | | BasicJsonWriter(std::ostream& out, uint8_t indent, const ALLOC& allocator = ALLOC()); |
85 | | |
86 | | /** |
87 | | * Constructor. |
88 | | * |
89 | | * \param out Stream to use for writing. |
90 | | * \param indent Indent as a string to be used for indentation. |
91 | | * \param allocator Allocator to use. |
92 | | */ |
93 | | BasicJsonWriter(std::ostream& out, const string<ALLOC>& indent, const ALLOC& allocator = ALLOC()); |
94 | | |
95 | | /** |
96 | | * Method generated by default. |
97 | | */ |
98 | 68 | ~BasicJsonWriter() override = default; |
99 | | |
100 | | /** |
101 | | * Copying and moving is disallowed! |
102 | | * \{ |
103 | | */ |
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; |
109 | | /** |
110 | | * \} |
111 | | */ |
112 | | |
113 | | /** |
114 | | * Sets custom item separator. |
115 | | * |
116 | | * Use with caution since setting of a wrong separator can lead to invalid JSON output. |
117 | | * |
118 | | * \param itemSeparator Item separator to set. |
119 | | */ |
120 | | void setItemSeparator(const string<ALLOC>& itemSeparator); |
121 | | |
122 | | /** |
123 | | * Sets custom key separator. |
124 | | * |
125 | | * Use with caution since setting of a wrong separator can lead to invalid JSON output. |
126 | | * |
127 | | * \param keySeparator Key separator to set. |
128 | | */ |
129 | | void setKeySeparator(const string<ALLOC>& keySeparator); |
130 | | |
131 | | /** |
132 | | * Sets preferred formatting for enumerable types. |
133 | | * |
134 | | * @param enumerableFormat Enumerable format to use. |
135 | | */ |
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 | | |
151 | | void visitValue(const IBasicReflectableConstPtr<ALLOC>& value, |
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; |
174 | | InplaceOptionalHolder<string<ALLOC>> m_indent; |
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 | | |
183 | | /** Typedef to JsonWriter provided for convenience - using default std::allocator<uint8_t>. */ |
184 | | /** \{ */ |
185 | | using JsonWriter = BasicJsonWriter<>; |
186 | | /** \} */ |
187 | | |
188 | | template <typename ALLOC> |
189 | | BasicJsonWriter<ALLOC>::BasicJsonWriter(std::ostream& out, const ALLOC& allocator) : |
190 | | BasicJsonWriter(out, NullOpt, allocator) |
191 | 28 | {} |
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 | 38 | {} |
197 | | |
198 | | template <typename ALLOC> |
199 | | BasicJsonWriter<ALLOC>::BasicJsonWriter(std::ostream& out, const string<ALLOC>& indent, |
200 | | const ALLOC& allocator) : |
201 | | BasicJsonWriter(out, InplaceOptionalHolder<string<ALLOC>>(indent), allocator) |
202 | 40 | {} |
203 | | |
204 | | template <typename ALLOC> |
205 | | BasicJsonWriter<ALLOC>::BasicJsonWriter(std::ostream& out, |
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 | 68 | {} |
213 | | |
214 | | template <typename ALLOC> |
215 | | void BasicJsonWriter<ALLOC>::setItemSeparator(const string<ALLOC>& itemSeparator) |
216 | 1 | { |
217 | 1 | m_itemSeparator = itemSeparator; |
218 | 1 | } |
219 | | |
220 | | template <typename ALLOC> |
221 | | void BasicJsonWriter<ALLOC>::setKeySeparator(const string<ALLOC>& keySeparator) |
222 | 1 | { |
223 | 1 | m_keySeparator = keySeparator; |
224 | 1 | } |
225 | | |
226 | | template <typename ALLOC> |
227 | | void BasicJsonWriter<ALLOC>::setEnumerableFormat(EnumerableFormat enumerableFormat) |
228 | 3 | { |
229 | 3 | m_enumerableFormat = enumerableFormat; |
230 | 3 | } |
231 | | |
232 | | template <typename ALLOC> |
233 | | void BasicJsonWriter<ALLOC>::beginRoot(const IBasicReflectableConstPtr<ALLOC>&) |
234 | 45 | { |
235 | 45 | beginObject(); |
236 | 45 | } |
237 | | |
238 | | template <typename ALLOC> |
239 | | void BasicJsonWriter<ALLOC>::endRoot(const IBasicReflectableConstPtr<ALLOC>&) |
240 | 45 | { |
241 | 45 | endObject(); |
242 | 45 | m_out.flush(); |
243 | 45 | } |
244 | | |
245 | | template <typename ALLOC> |
246 | | void BasicJsonWriter<ALLOC>::beginArray(const IBasicReflectableConstPtr<ALLOC>&, |
247 | | const BasicFieldInfo<ALLOC>& fieldInfo) |
248 | 3 | { |
249 | 3 | beginItem(); |
250 | | |
251 | 3 | writeKey(fieldInfo.schemaName); |
252 | | |
253 | 3 | beginArray(); |
254 | 3 | } |
255 | | |
256 | | template <typename ALLOC> |
257 | | void BasicJsonWriter<ALLOC>::endArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) |
258 | 3 | { |
259 | 3 | endArray(); |
260 | | |
261 | 3 | endItem(); |
262 | 3 | } |
263 | | |
264 | | template <typename ALLOC> |
265 | | void BasicJsonWriter<ALLOC>::beginCompound(const IBasicReflectableConstPtr<ALLOC>&, |
266 | | const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) |
267 | 6 | { |
268 | 6 | beginItem(); |
269 | | |
270 | 6 | if (elementIndex == WALKER_NOT_ELEMENT) |
271 | 5 | writeKey(fieldInfo.schemaName); |
272 | | |
273 | 6 | beginObject(); |
274 | 6 | } |
275 | | |
276 | | template <typename ALLOC> |
277 | | void BasicJsonWriter<ALLOC>::endCompound(const IBasicReflectableConstPtr<ALLOC>&, |
278 | | const BasicFieldInfo<ALLOC>&, size_t) |
279 | 6 | { |
280 | 6 | endObject(); |
281 | | |
282 | 6 | endItem(); |
283 | 6 | } |
284 | | |
285 | | template <typename ALLOC> |
286 | | void BasicJsonWriter<ALLOC>::visitValue(const IBasicReflectableConstPtr<ALLOC>& value, |
287 | | const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) |
288 | 85 | { |
289 | 85 | beginItem(); |
290 | | |
291 | 85 | if (elementIndex == WALKER_NOT_ELEMENT) |
292 | 81 | writeKey(fieldInfo.schemaName); |
293 | | |
294 | 85 | writeValue(value); |
295 | | |
296 | 85 | endItem(); |
297 | 85 | } |
298 | | |
299 | | template <typename ALLOC> |
300 | | void BasicJsonWriter<ALLOC>::beginItem() |
301 | 108 | { |
302 | 108 | if (!m_isFirst) |
303 | 29 | m_out.write(m_itemSeparator.data(), static_cast<std::streamsize>(m_itemSeparator.size())); |
304 | | |
305 | 108 | if (m_indent.hasValue()) |
306 | 43 | m_out.put('\n'); |
307 | | |
308 | 108 | writeIndent(); |
309 | 108 | } |
310 | | |
311 | | template <typename ALLOC> |
312 | | void BasicJsonWriter<ALLOC>::endItem() |
313 | 107 | { |
314 | 107 | m_isFirst = false; |
315 | 107 | } |
316 | | |
317 | | template <typename ALLOC> |
318 | | void BasicJsonWriter<ALLOC>::beginObject() |
319 | 55 | { |
320 | 55 | m_out.put('{'); |
321 | | |
322 | 55 | m_isFirst = true; |
323 | 55 | m_level += 1; |
324 | 55 | } |
325 | | |
326 | | template <typename ALLOC> |
327 | | void BasicJsonWriter<ALLOC>::endObject() |
328 | 55 | { |
329 | 55 | if (m_indent.hasValue()) |
330 | 43 | m_out.put('\n'); |
331 | | |
332 | 55 | m_level -= 1; |
333 | | |
334 | 55 | writeIndent(); |
335 | | |
336 | 55 | m_out.put('}'); |
337 | 55 | } |
338 | | |
339 | | template <typename ALLOC> |
340 | | void BasicJsonWriter<ALLOC>::beginArray() |
341 | 7 | { |
342 | 7 | m_out.put('['); |
343 | | |
344 | 7 | m_isFirst = true; |
345 | 7 | m_level += 1; |
346 | 7 | } |
347 | | |
348 | | template <typename ALLOC> |
349 | | void BasicJsonWriter<ALLOC>::endArray() |
350 | 7 | { |
351 | 7 | if (m_indent.hasValue()) |
352 | 1 | m_out.put('\n'); |
353 | | |
354 | 7 | m_level -= 1; |
355 | | |
356 | 7 | writeIndent(); |
357 | | |
358 | 7 | m_out.put(']'); |
359 | 7 | } |
360 | | |
361 | | template <typename ALLOC> |
362 | | void BasicJsonWriter<ALLOC>::writeIndent() |
363 | 170 | { |
364 | 170 | if (m_indent.hasValue()) |
365 | 87 | { |
366 | 87 | const auto& indent = m_indent.value(); |
367 | 87 | if (!indent.empty()) |
368 | 82 | { |
369 | 129 | for (size_t i = 0; i < m_level; ++i47 ) |
370 | 47 | m_out.write(indent.data(), static_cast<std::streamsize>(indent.size())); |
371 | 82 | } |
372 | 87 | } |
373 | 170 | } |
374 | | |
375 | | template <typename ALLOC> |
376 | | void BasicJsonWriter<ALLOC>::writeKey(StringView key) |
377 | 95 | { |
378 | 95 | JsonEncoder::encodeString(m_out, key); |
379 | 95 | m_out.write(m_keySeparator.data(), static_cast<std::streamsize>(m_keySeparator.size())); |
380 | 95 | m_out.flush(); |
381 | 95 | } |
382 | | |
383 | | template <typename ALLOC> |
384 | | void BasicJsonWriter<ALLOC>::writeValue(const IBasicReflectableConstPtr<ALLOC>& reflectable) |
385 | 85 | { |
386 | 85 | if (!reflectable) |
387 | 1 | { |
388 | 1 | JsonEncoder::encodeNull(m_out); |
389 | 1 | return; |
390 | 1 | } |
391 | | |
392 | 84 | const IBasicTypeInfo<ALLOC>& typeInfo = reflectable->getTypeInfo(); |
393 | 84 | switch (typeInfo.getCppType()) |
394 | 84 | { |
395 | 1 | case CppType::BOOL: |
396 | 1 | JsonEncoder::encodeBool(m_out, reflectable->getBool()); |
397 | 1 | break; |
398 | 1 | case CppType::INT8: |
399 | 2 | case CppType::INT16: |
400 | 3 | case CppType::INT32: |
401 | 4 | case CppType::INT64: |
402 | 4 | JsonEncoder::encodeIntegral(m_out, reflectable->toInt()); |
403 | 4 | break; |
404 | 1 | case CppType::UINT8: |
405 | 2 | case CppType::UINT16: |
406 | 13 | case CppType::UINT32: |
407 | 14 | case CppType::UINT64: |
408 | 14 | JsonEncoder::encodeIntegral(m_out, reflectable->toUInt()); |
409 | 14 | break; |
410 | 1 | case CppType::FLOAT: |
411 | 1 | JsonEncoder::encodeFloatingPoint(m_out, static_cast<double>(reflectable->getFloat())); |
412 | 1 | break; |
413 | 1 | case CppType::DOUBLE: |
414 | 1 | JsonEncoder::encodeFloatingPoint(m_out, reflectable->getDouble()); |
415 | 1 | break; |
416 | 2 | case CppType::BYTES: |
417 | 2 | writeBytes(reflectable->getBytes()); |
418 | 2 | break; |
419 | 39 | case CppType::STRING: |
420 | 39 | JsonEncoder::encodeString(m_out, reflectable->getStringView()); |
421 | 39 | break; |
422 | 2 | case CppType::BIT_BUFFER: |
423 | 2 | writeBitBuffer(reflectable->getBitBuffer()); |
424 | 2 | break; |
425 | 12 | case CppType::ENUM: |
426 | 12 | if (m_enumerableFormat == EnumerableFormat::STRING) |
427 | 7 | writeStringifiedEnum(reflectable); |
428 | 5 | else if (TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType())) |
429 | 3 | JsonEncoder::encodeIntegral(m_out, reflectable->toInt()); |
430 | 2 | else |
431 | 2 | JsonEncoder::encodeIntegral(m_out, reflectable->toUInt()); |
432 | 12 | break; |
433 | 7 | case CppType::BITMASK: |
434 | 7 | if (m_enumerableFormat == EnumerableFormat::STRING) |
435 | 5 | writeStringifiedBitmask(reflectable); |
436 | 2 | else |
437 | 2 | JsonEncoder::encodeIntegral(m_out, reflectable->toUInt()); |
438 | 7 | break; |
439 | 1 | default: |
440 | 1 | throw CppRuntimeException("JsonWriter: Unexpected not-null value of type '") << |
441 | 1 | typeInfo.getSchemaName() << "'!"; |
442 | 84 | } |
443 | | |
444 | 83 | m_out.flush(); |
445 | 83 | } |
446 | | |
447 | | template <typename ALLOC> |
448 | | void BasicJsonWriter<ALLOC>::writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer) |
449 | 2 | { |
450 | 2 | beginObject(); |
451 | 2 | beginItem(); |
452 | 2 | writeKey("buffer"_sv); |
453 | 2 | beginArray(); |
454 | 2 | Span<const uint8_t> buffer = bitBuffer.getData(); |
455 | 2 | for (uint8_t element : buffer) |
456 | 4 | { |
457 | 4 | beginItem(); |
458 | 4 | JsonEncoder::encodeIntegral(m_out, element); |
459 | 4 | endItem(); |
460 | 4 | } |
461 | 2 | endArray(); |
462 | 2 | endItem(); |
463 | 2 | beginItem(); |
464 | 2 | writeKey("bitSize"_sv); |
465 | 2 | JsonEncoder::encodeIntegral(m_out, bitBuffer.getBitSize()); |
466 | 2 | endItem(); |
467 | 2 | endObject(); |
468 | 2 | } |
469 | | |
470 | | template <typename ALLOC> |
471 | | void BasicJsonWriter<ALLOC>::writeBytes(Span<const uint8_t> value) |
472 | 2 | { |
473 | 2 | beginObject(); |
474 | 2 | beginItem(); |
475 | 2 | writeKey("buffer"_sv); |
476 | 2 | beginArray(); |
477 | 2 | for (uint8_t byte : value) |
478 | 4 | { |
479 | 4 | beginItem(); |
480 | 4 | JsonEncoder::encodeIntegral(m_out, byte); |
481 | 4 | endItem(); |
482 | 4 | } |
483 | 2 | endArray(); |
484 | 2 | endItem(); |
485 | 2 | endObject(); |
486 | 2 | } |
487 | | |
488 | | template <typename ALLOC> |
489 | | void BasicJsonWriter<ALLOC>::writeStringifiedEnum(const IBasicReflectableConstPtr<ALLOC>& reflectable) |
490 | 7 | { |
491 | 7 | const auto& typeInfo = reflectable->getTypeInfo(); |
492 | 7 | const uint64_t enumValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()) ? |
493 | 4 | static_cast<uint64_t>(reflectable->toInt()) : reflectable->toUInt()3 ; |
494 | 7 | for (const auto& itemInfo : typeInfo.getEnumItems()) |
495 | 14 | { |
496 | 14 | if (itemInfo.value == enumValue) |
497 | 5 | { |
498 | | // exact match |
499 | 5 | JsonEncoder::encodeString(m_out, itemInfo.schemaName); |
500 | 5 | return; |
501 | 5 | } |
502 | 14 | } |
503 | | |
504 | | // no match |
505 | 2 | string<ALLOC> stringValue = TypeInfoUtil::isSigned(typeInfo.getUnderlyingType().getCppType()) |
506 | 2 | ? toString(reflectable->toInt(), get_allocator())1 |
507 | 2 | : toString(reflectable->toUInt(), get_allocator())1 ; |
508 | 2 | stringValue.append(" /* no match */"); |
509 | 2 | JsonEncoder::encodeString(m_out, stringValue); |
510 | 2 | } |
511 | | |
512 | | template <typename ALLOC> |
513 | | void BasicJsonWriter<ALLOC>::writeStringifiedBitmask(const IBasicReflectableConstPtr<ALLOC>& reflectable) |
514 | 5 | { |
515 | 5 | string<ALLOC> stringValue(get_allocator()); |
516 | 5 | const auto& typeInfo = reflectable->getTypeInfo(); |
517 | 5 | const uint64_t bitmaskValue = reflectable->toUInt(); |
518 | 5 | uint64_t valueCheck = 0; |
519 | 5 | for (const auto& itemInfo : typeInfo.getBitmaskValues()) |
520 | 15 | { |
521 | 15 | if ((itemInfo.value != 0 && (bitmaskValue & itemInfo.value) == itemInfo.value10 ) || |
522 | 15 | (10 itemInfo.value == 010 && bitmaskValue == 05 )) |
523 | 6 | { |
524 | 6 | valueCheck |= itemInfo.value; |
525 | 6 | if (!stringValue.empty()) |
526 | 2 | stringValue += " | "; |
527 | 6 | stringValue += toString(itemInfo.schemaName, get_allocator()); |
528 | 6 | } |
529 | 15 | } |
530 | | |
531 | 5 | if (stringValue.empty()) |
532 | 1 | { |
533 | | // no match |
534 | 1 | stringValue.append(toString(bitmaskValue, get_allocator())); |
535 | 1 | stringValue.append(" /* no match */"); |
536 | 1 | } |
537 | 4 | else if (bitmaskValue != valueCheck) |
538 | 1 | { |
539 | | // partial match |
540 | 1 | stringValue = toString(bitmaskValue, get_allocator()) |
541 | 1 | .append(" /* partial match: ") |
542 | 1 | .append(stringValue) |
543 | 1 | .append(" */"); |
544 | 1 | } |
545 | | // else exact match |
546 | | |
547 | 5 | JsonEncoder::encodeString(m_out, stringValue); |
548 | 5 | } |
549 | | |
550 | | } // namespace zserio |
551 | | |
552 | | #endif // ZSERIO_JSON_WRITER_H_INC |