Reflection for RapidJSON 0.0.16
Reflection for serializing/deserializing with RapidJSON
Loading...
Searching...
No Matches
reflector.h
Go to the documentation of this file.
1#ifndef REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
2#define REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
3
10#include "../traits.h"
11
12#include <c++utilities/application/global.h>
13
14#include <rapidjson/document.h>
15#include <rapidjson/rapidjson.h>
16#include <rapidjson/stringbuffer.h>
17#include <rapidjson/writer.h>
18
19#include <limits>
20#include <map>
21#include <memory>
22#include <optional>
23#include <set>
24#include <string>
25#include <tuple>
26#include <unordered_map>
27#include <unordered_set>
28#include <utility>
29#include <variant>
30
31#include "./errorhandling.h"
32
33namespace ReflectiveRapidJSON {
34
35template <typename Type> struct JsonSerializable;
36
40template <typename T> struct AdaptedJsonSerializable : public Traits::Bool<false> {
41 static constexpr const char *name = "AdaptedJsonSerializable";
42 static constexpr const char *qualifiedName = "ReflectiveRapidJSON::AdaptedJsonSerializable";
43};
44
48namespace JsonReflector {
49
53constexpr RAPIDJSON_NAMESPACE::SizeType rapidJsonSize(std::size_t size)
54{
55 return size > std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max() ? std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max()
56 : static_cast<RAPIDJSON_NAMESPACE::SizeType>(size);
57}
58
62inline RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
63{
64 RAPIDJSON_NAMESPACE::StringBuffer buffer;
65 RAPIDJSON_NAMESPACE::Writer<RAPIDJSON_NAMESPACE::StringBuffer> writer(buffer);
66 document.Accept(writer);
67 return buffer;
68}
69
73inline RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
74{
75 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
76 const RAPIDJSON_NAMESPACE::ParseResult parseRes = document.Parse(json, jsonSize);
77 if (parseRes.IsError()) {
78 throw parseRes;
79 }
80 return document;
81}
82
83// define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
84template <typename Type>
85using IsBuiltInType = Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>, std::is_enum<Type>,
86 Traits::IsSpecializingAnyOf<Type, std::tuple, std::pair>, Traits::IsIteratable<Type>,
87 Traits::IsSpecializingAnyOf<Type, std::unique_ptr, std::shared_ptr, std::weak_ptr, std::optional>, IsVariant<Type>>;
88template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
89
90// define trait to check for custom structs/classes which are JSON serializable
91// NOTE: the check for Traits::IsComplete is required because std::is_base_of fails for incomplete types when using GCC
92template <typename Type>
94 = Traits::Any<Traits::Not<Traits::IsComplete<Type>>, std::is_base_of<JsonSerializable<Type>, Type>, AdaptedJsonSerializable<Type>>;
95
96// define functions to "push" values to a RapidJSON array or object
97
101template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
102void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
103
107template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> * = nullptr>
108void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
109
113template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> * = nullptr>
114void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
115
119template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> * = nullptr>
120void push(
121 const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
122
126template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> * = nullptr>
127void push(
128 const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
129
134template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
135void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
136
140template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> *>
141inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
142{
143 value.SetObject();
144 RAPIDJSON_NAMESPACE::Value::Object obj(value.GetObject());
145 push(reflectable, obj, allocator);
146}
147
151template <typename Type,
152 Traits::EnableIfAny<
153 Traits::All<std::is_integral<Type>, Traits::Not<std::is_same<Type, std::uint8_t>>, Traits::Not<std::is_same<Type, std::int8_t>>>,
154 std::is_floating_point<Type>> * = nullptr>
155inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
156{
157 value.Set(reflectable, allocator);
158}
159
163template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::uint8_t>, std::is_same<Type, std::int8_t>> * = nullptr>
164inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
165{
166 value.Set(static_cast<int>(reflectable), allocator);
167}
168
172template <typename Type, Traits::EnableIfAny<std::is_enum<Type>> * = nullptr>
173inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
174{
175 value.Set(static_cast<Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, std::uint64_t, std::int64_t>>(reflectable),
176 allocator);
177}
178
182template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>, std::is_same<Type, const char *const &>> * = nullptr>
183inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
184{
185 if (reflectable) {
186 value.SetString(reflectable, allocator);
187 } else {
188 value.SetNull();
189 }
190}
191
195template <typename Type, Traits::EnableIf<std::is_same<Type, std::string_view>> * = nullptr>
196inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
197{
198 if (reflectable.data()) {
199 value.SetString(reflectable.data(), rapidJsonSize(reflectable.size()), allocator);
200 } else {
201 value.SetNull();
202 }
203}
204
208template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
209inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
210{
211 value.SetString(reflectable.data(), rapidJsonSize(reflectable.size()), allocator);
212}
213
217template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::HasSize<Type>> * = nullptr>
218void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
219{
220 value.SetArray();
221 RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
222 array.Reserve(rapidJsonSize(reflectable.size()), allocator);
223 for (const auto &item : reflectable) {
224 push(item, array, allocator);
225 }
226}
227
231template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::HasSize<Type>>> * = nullptr>
232void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
233{
234 value.SetArray();
235 RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
236 for (const auto &item : reflectable) {
237 push(item, array, allocator);
238 }
239}
240
244template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>> * = nullptr>
245void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
246{
247 value.SetObject();
248 RAPIDJSON_NAMESPACE::Value::Object object(value.GetObject());
249 for (const auto &item : reflectable) {
250 push(item.second, item.first.data(), object, allocator);
251 }
252}
253
257template <typename Type, Traits::EnableIfAny<IsMultiMapOrHash<Type>> * = nullptr>
258void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
259{
260 value.SetObject();
261 for (const auto &item : reflectable) {
262 const auto memberName = RAPIDJSON_NAMESPACE::Value::StringRefType(item.first.data(), rapidJsonSize(item.first.size()));
263 const auto existingMember = value.FindMember(memberName);
264 const auto arrayAlreadyExists
265 = existingMember != value.MemberEnd() && existingMember->value.GetType() == RAPIDJSON_NAMESPACE::Type::kArrayType;
266 auto newArrayValue = RAPIDJSON_NAMESPACE::Value{ RAPIDJSON_NAMESPACE::kArrayType };
267 RAPIDJSON_NAMESPACE::Value::Array array = arrayAlreadyExists ? existingMember->value.GetArray() : newArrayValue.GetArray();
268 push(item.second, array, allocator);
269 if (!arrayAlreadyExists) {
270 value.AddMember(memberName, newArrayValue, allocator);
271 }
272 }
273}
275namespace Detail {
276
280template <class Tuple, std::size_t N> struct TuplePushHelper {
281 static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
282 {
283 TuplePushHelper<Tuple, N - 1>::push(tuple, value, allocator);
284 JsonReflector::push(std::get<N - 1>(tuple), value, allocator);
285 }
286};
288template <class Tuple> struct TuplePushHelper<Tuple, 1> {
289 static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
290 {
291 JsonReflector::push(std::get<0>(tuple), value, allocator);
292 }
293};
294} // namespace Detail
295
299template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>> * = nullptr>
300void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
301{
302 value.SetArray();
303 RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
304 array.Reserve(std::tuple_size<Type>::value, allocator);
306}
307
311template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr>
312void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
313{
314 value.SetArray();
315 RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
316 array.Reserve(2, allocator);
317 push(reflectable.first, array, allocator);
318 push(reflectable.second, array, allocator);
319}
320
324template <typename Type,
325 Traits::EnableIfAny<Traits::IsSpecializingAnyOf<Type, std::unique_ptr, std::shared_ptr, std::weak_ptr, std::optional>> * = nullptr>
326void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
327{
328 if (!reflectable) {
329 value.SetNull();
330 return;
331 }
332 push(*reflectable, value, allocator);
333}
334
338template <typename Type, Traits::EnableIf<IsVariant<Type>> * = nullptr>
339void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
340{
341 if (reflectable.valueless_by_exception()) {
342 value.SetNull();
343 return;
344 }
345
346 RAPIDJSON_NAMESPACE::Value index, data;
347 index.SetUint64(reflectable.index());
348 std::visit(
349 [&data, &allocator](const auto &reflectableOfActualType) {
350 if constexpr (!std::is_same_v<std::decay_t<decltype(reflectableOfActualType)>, std::monostate>) {
351 push(reflectableOfActualType, data, allocator);
352 } else {
353 CPP_UTILITIES_UNUSED(data)
354 CPP_UTILITIES_UNUSED(allocator)
355 }
356 },
357 reflectable);
358
359 value.SetObject();
360 value.AddMember("index", index, allocator);
361 value.AddMember("data", data, allocator);
362}
363
367template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> *>
368void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
369{
370 RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
371 RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
372 push(reflectable, object, allocator);
373 value.PushBack(objectValue, allocator);
374}
375
379template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> *>
380void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
381{
382 RAPIDJSON_NAMESPACE::Value genericValue;
383 push(reflectable, genericValue, allocator);
384 value.PushBack(genericValue, allocator);
385}
386
390template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> *>
391void push(
392 const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
393{
394 RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
395 RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
396 push(reflectable, object, allocator);
397 value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), objectValue, allocator);
398}
399
403template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> *>
404void push(
405 const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
406{
407 RAPIDJSON_NAMESPACE::Value genericValue;
408 push(reflectable, genericValue, allocator);
409 value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), genericValue, allocator);
410}
411
412// define functions to "pull" values from a RapidJSON array or object
413
418template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
419void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
420 JsonDeserializationErrors *errors);
421
425template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
426void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
427
431template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::IsReservable<Type>>> * = nullptr>
432void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
433
437template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::IsReservable<Type>> * = nullptr>
438void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
439
443template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr>
444void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
445
449template <typename Type, Traits::EnableIf<IsSet<Type>> * = nullptr>
450void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
451
455template <typename Type, Traits::EnableIf<IsMultiSet<Type>> * = nullptr>
456void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
457
461template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> * = nullptr>
462void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
463
467template <typename Type, Traits::EnableIf<IsMultiMapOrHash<Type>> * = nullptr>
468void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
469
473template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>> * = nullptr>
474void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
475
479template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr>
480void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
481
485template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * = nullptr>
486void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
487
491template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr>
492void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
493
497template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::optional>> * = nullptr>
498void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
499
503template <typename Type, Traits::EnableIf<IsVariant<Type>> * = nullptr>
504void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
505
509template <typename Type>
510inline void pull(
511 Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors);
512
518template <typename Type>
519inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
520 JsonDeserializationErrors *errors);
521
525template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> *>
526void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
527
531template <typename Type,
532 Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Not<std::is_same<Type, std::uint8_t>>,
533 Traits::Not<std::is_same<Type, std::int8_t>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>> * = nullptr>
534inline void pull(
535 Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
536{
537 if (!value.IsNumber()) {
538 if (errors) {
539 errors->reportTypeMismatch<Type>(value.GetType());
540 }
541 return;
542 }
543 reflectable = value.Is<Type>() ? value.Get<Type>() : static_cast<Type>(value.GetDouble());
544}
545
549template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::uint8_t>, std::is_same<Type, std::int8_t>> * = nullptr>
550inline void pull(
551 Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
552{
553 int i = 0;
554 pull(i, value, errors);
555 if (value.IsNumber()) {
556 reflectable = static_cast<Type>(i);
557 }
558}
559
563template <typename Type, Traits::EnableIf<std::is_same<Type, bool>> * = nullptr>
564inline void pull(
565 Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
566{
567 if (!value.IsBool()) {
568 if (errors) {
569 errors->reportTypeMismatch<Type>(value.GetType());
570 }
571 return;
572 }
573 reflectable = value.GetBool();
574}
575
580template <typename Type, Traits::EnableIfAny<std::is_enum<Type>> * = nullptr>
581inline void pull(
582 Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
583{
584 using ExpectedType = Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, std::uint64_t, std::int64_t>;
585 if (!value.Is<ExpectedType>()) {
586 if (errors) {
587 errors->reportTypeMismatch<ExpectedType>(value.GetType());
588 }
589 return;
590 }
591 reflectable = static_cast<Type>(value.Get<ExpectedType>());
592}
593
597template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
598inline void pull(
599 Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
600{
601 if (!value.IsString()) {
602 if (errors) {
603 errors->reportTypeMismatch<std::string>(value.GetType());
604 }
605 return;
606 }
607 reflectable = value.GetString();
608}
609
614template <typename Type,
615 Traits::EnableIfAny<std::is_same<Type, const char *>, std::is_same<Type, const char *const &>, std::is_same<Type, std::string_view>> * = nullptr>
616inline void pull(Type &, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
617{
618 if (!value.IsString()) {
619 if (errors) {
620 errors->reportTypeMismatch<std::string>(value.GetType());
621 }
622 return;
623 }
624}
625
629template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::IsReservable<Type>>> *>
630void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
631{
632 if (!value.IsArray()) {
633 if (errors) {
634 errors->reportTypeMismatch<Type>(value.GetType());
635 }
636 return;
637 }
638 pull(reflectable, value.GetArray(), errors);
639}
640
644template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::IsReservable<Type>> *>
645void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
646{
647 if (!value.IsArray()) {
648 if (errors) {
649 errors->reportTypeMismatch<Type>(value.GetType());
650 }
651 return;
652 }
653 auto array = value.GetArray();
654 reflectable.reserve(array.Size());
655 pull(reflectable, array, errors);
656}
657
661template <typename Type, Traits::EnableIf<IsArray<Type>> *>
662void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
663{
664 // clear previous contents of the array
665 reflectable.clear();
666
667 // pull all array elements of the specified value
668 std::size_t index = 0;
669 for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
670 // set error context for current index
671 if (errors) {
672 errors->currentIndex = index;
673 }
674 ++index;
675 reflectable.emplace_back();
676 pull(reflectable.back(), item, errors);
677 }
678
679 // clear error context
680 if (errors) {
682 }
683}
684
688template <typename Type, Traits::EnableIf<IsMultiSet<Type>> *>
689void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
690{
691 // clear previous contents of the array
692 reflectable.clear();
693
694 // pull all array elements of the specified value
695 std::size_t index = 0;
696 for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
697 // set error context for current index
698 if (errors) {
699 errors->currentIndex = index;
700 }
701 ++index;
702 typename Type::value_type itemObj;
703 pull(itemObj, item, errors);
704 reflectable.emplace(std::move(itemObj));
705 }
706
707 // clear error context
708 if (errors) {
710 }
711}
712
716template <typename Type, Traits::EnableIf<IsSet<Type>> *>
717void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
718{
719 // clear previous contents of the array
720 reflectable.clear();
721
722 // pull all array elements of the specified value
723 std::size_t index = 0;
724 for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
725 // set error context for current index
726 if (errors) {
727 errors->currentIndex = index;
728 }
729 ++index;
730 typename Type::value_type itemObj;
731 pull(itemObj, item, errors);
732 if (!reflectable.emplace(std::move(itemObj)).second) {
733 errors->reportUnexpectedDuplicate(JsonType::Array);
734 }
735 }
736
737 // clear error context
738 if (errors) {
739 errors->currentIndex = JsonDeserializationError::noIndex;
740 }
741}
742
746template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> *>
747void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
748{
749 if (!value.IsObject()) {
750 if (errors) {
751 errors->reportTypeMismatch<Type>(value.GetType());
752 }
753 return;
754 }
755 auto obj = value.GetObject();
756 for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
757 pull(reflectable[i->name.GetString()], i->value, errors);
758 }
759}
760
764template <typename Type, Traits::EnableIf<IsMultiMapOrHash<Type>> *>
765void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
766{
767 if (!value.IsObject()) {
768 if (errors) {
769 errors->reportTypeMismatch<Type>(value.GetType());
770 }
771 return;
772 }
773 auto obj = value.GetObject();
774 for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
775 if (i->value.GetType() != RAPIDJSON_NAMESPACE::kArrayType) {
776 auto insertedIterator = reflectable.insert(typename Type::value_type(i->name.GetString(), typename Type::mapped_type()));
777 pull(insertedIterator->second, i->value, errors);
778 continue;
779 }
780 const auto array = i->value.GetArray();
781 for (const auto &arrayValue : array) {
782 auto insertedIterator = reflectable.insert(typename Type::value_type(i->name.GetString(), typename Type::mapped_type()));
783 pull(insertedIterator->second, arrayValue, errors);
784 }
785 }
786}
787
788namespace Detail {
789
794template <class Tuple, std::size_t N> struct TuplePullHelper {
795 static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
796 {
797 TuplePullHelper<Tuple, N - 1>::pull(tuple, value, errors);
798 JsonReflector::pull<typename std::tuple_element<N - 1, Tuple>::type>(std::get<N - 1>(tuple), value[N - 1], errors);
799 }
800};
802template <class Tuple> struct TuplePullHelper<Tuple, 1> {
803 static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
804 {
805 JsonReflector::pull<typename std::tuple_element<0, Tuple>::type>(std::get<0>(tuple), value[0], errors);
806 }
807};
808} // namespace Detail
809
813template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>> *>
814void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
815{
816 if (!value.IsArray()) {
817 if (errors) {
818 errors->reportTypeMismatch<Type>(value.GetType());
819 }
820 return;
821 }
822 const auto array = value.GetArray();
823 if (array.Size() != std::tuple_size<Type>::value) {
824 if (errors) {
825 // FIXME: report expected and actual size
826 errors->reportArraySizeMismatch();
827 }
828 return;
829 }
830 Detail::TuplePullHelper<Type, std::tuple_size<Type>::value>::pull(reflectable, array, errors);
831}
832
836template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> *>
837void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
838{
839 if (!value.IsArray()) {
840 if (errors) {
841 errors->reportTypeMismatch<Type>(value.GetType());
842 }
843 return;
844 }
845 const auto array = value.GetArray();
846 if (array.Size() != 2) {
847 if (errors) {
848 // FIXME: report expected and actual size
849 errors->reportArraySizeMismatch();
850 }
851 return;
852 }
853 pull(reflectable.first, array[0], errors);
854 pull(reflectable.second, array[1], errors);
855}
856
860template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> *>
861void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
862{
863 if (value.IsNull()) {
864 reflectable.reset();
865 return;
866 }
867 reflectable = std::make_unique<typename Type::element_type>();
868 pull(*reflectable, value, errors);
869}
870
874template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> *>
875void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
876{
877 if (value.IsNull()) {
878 reflectable.reset();
879 return;
880 }
881 reflectable = std::make_shared<typename Type::element_type>();
882 pull(*reflectable, value, errors);
883}
884
888template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::optional>> *>
889void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
890{
891 if (value.IsNull()) {
892 reflectable.reset();
893 } else {
894 pull(reflectable.emplace(), value, errors);
895 }
896}
897
899namespace Detail {
900template <typename Variant, std::size_t compiletimeIndex = 0>
901void assignVariantValueByRuntimeIndex(std::size_t runtimeIndex, Variant &variant,
902 const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
903{
904 if constexpr (compiletimeIndex < std::variant_size_v<Variant>) {
905 if (compiletimeIndex == runtimeIndex) {
906 if constexpr (std::is_same_v<std::variant_alternative_t<compiletimeIndex, Variant>, std::monostate>) {
907 variant = std::monostate{};
908 } else {
909 pull(variant.template emplace<compiletimeIndex>(), value, errors);
910 }
911 } else {
912 assignVariantValueByRuntimeIndex<Variant, compiletimeIndex + 1>(runtimeIndex, variant, value, errors);
913 }
914 } else {
915 if (errors) {
916 errors->emplace_back(JsonDeserializationErrorKind::InvalidVariantIndex, JsonType::Number, JsonType::Number, errors->currentRecord,
917 errors->currentMember, errors->currentIndex);
918 }
919 }
920}
921} // namespace Detail
923
927template <typename Type, Traits::EnableIf<IsVariant<Type>> *>
928void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
929{
930 if (!value.IsObject()) {
931 if (errors) {
932 errors->reportTypeMismatch<Type>(value.GetType());
933 }
934 return;
935 }
936
937 auto obj = value.GetObject();
938 auto indexIterator = obj.FindMember("index");
939 auto dataIterator = obj.FindMember("data");
940 if (indexIterator == obj.MemberEnd() || dataIterator == obj.MemberEnd()) {
941 if (errors) {
943 errors->currentMember, errors->currentIndex);
944 }
945 return;
946 }
947 const auto &indexValue = indexIterator->value;
948 if (!indexValue.IsUint64()) {
949 if (errors) {
950 errors->emplace_back(JsonDeserializationErrorKind::InvalidVariantIndex, JsonType::Number, jsonType(indexValue.GetType()),
951 errors->currentRecord, errors->currentMember, errors->currentIndex);
952 }
953 return;
954 }
955 Detail::assignVariantValueByRuntimeIndex(indexValue.GetUint64(), reflectable, dataIterator->value, errors);
956}
957
961template <typename Type>
962inline void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
963{
964 pull<Type>(reflectable, *value, errors);
965 ++value;
966}
967
973template <typename Type>
974inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
976{
977 // find member
978 const auto member = value.FindMember(name);
979 if (member == value.MemberEnd()) {
980 return; // TODO: handle member missing
981 }
982
983 // set error context for current member
984 const char *previousMember = nullptr;
985 if (errors) {
986 previousMember = errors->currentMember;
987 errors->currentMember = name;
988 }
989
990 // actually pull value for member
991 pull<Type>(reflectable, member->value, errors);
992
993 // restore previous error context
994 if (errors) {
995 errors->currentMember = previousMember;
996 }
997}
998
1002template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> *>
1003void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
1004{
1005 if (!value.IsObject()) {
1006 if (errors) {
1007 errors->reportTypeMismatch<Type>(value.GetType());
1008 }
1009 return;
1010 }
1011 pull(reflectable, value.GetObject(), errors);
1012}
1013
1014// define functions providing high-level JSON serialization
1015
1019template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
1020RAPIDJSON_NAMESPACE::Document toJsonDocument(const Type &reflectable)
1021{
1022 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
1023 push(reflectable, document, document.GetAllocator());
1024 return document;
1025}
1026
1030template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>> * = nullptr>
1031RAPIDJSON_NAMESPACE::Document toJsonDocument(Type reflectable)
1032{
1033 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType);
1034 document.Set(reflectable, document.GetAllocator());
1035 return document;
1036}
1037
1041template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
1042RAPIDJSON_NAMESPACE::Document toJsonDocument(const std::string &reflectable)
1043{
1044 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
1045 document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator());
1046 return document;
1047}
1048
1052template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>> * = nullptr>
1053RAPIDJSON_NAMESPACE::Document toJsonDocument(const char *reflectable)
1054{
1055 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
1056 document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator());
1057 return document;
1058}
1059
1063template <typename Type, Traits::EnableIf<std::is_same<Type, std::string_view>> * = nullptr>
1064RAPIDJSON_NAMESPACE::Document toJsonDocument(std::string_view reflectable)
1065{
1066 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
1067 document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator());
1068 return document;
1069}
1070
1074template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr> RAPIDJSON_NAMESPACE::Document toJsonDocument(const Type &reflectable)
1075{
1076 RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
1077 push(reflectable, document, document.GetAllocator());
1078 return document;
1079}
1080
1084template <typename Type,
1085 Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>, std::is_integral<Type>, std::is_floating_point<Type>,
1086 Traits::IsString<Type>, IsArray<Type>> * = nullptr>
1087RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
1088{
1089 auto document(toJsonDocument(reflectable));
1090 return serializeJsonDocToString(document);
1091}
1092
1093// define functions providing high-level JSON deserialization
1094
1098template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
1099Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
1100{
1101 RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
1102 if (!doc.IsObject()) {
1103 if (errors) {
1104 errors->reportTypeMismatch<Type>(doc.GetType());
1105 }
1106 return Type();
1107 }
1108
1109 Type res;
1110 pull<Type>(res, doc.GetObject(), errors);
1111 return res;
1112}
1113
1117template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>> * = nullptr>
1118Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
1119{
1120 RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
1121 if (!doc.Is<Type>()) {
1122 if (errors) {
1123 errors->reportTypeMismatch<Type>(doc.GetType());
1124 }
1125 return Type();
1126 }
1127
1128 return doc.Get<Type>();
1129}
1130
1134template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
1135Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
1136{
1137 RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
1138 if (!doc.IsString()) {
1139 if (errors) {
1140 errors->reportTypeMismatch<Type>(doc.GetType());
1141 }
1142 return Type();
1143 }
1144
1145 return doc.GetString();
1146}
1147
1151template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr>
1152Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
1153{
1154 RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
1155 if (!doc.IsArray()) {
1156 if (errors) {
1157 errors->reportTypeMismatch<Type>(doc.GetType());
1158 }
1159 return Type();
1160 }
1161
1162 Type res;
1163 pull<Type>(res, doc.GetArray(), errors);
1164 return res;
1165}
1166
1170template <typename Type> Type fromJson(const char *json, JsonDeserializationErrors *errors = nullptr)
1171{
1172 return fromJson<Type>(json, std::strlen(json), errors);
1173}
1174
1178template <typename Type> Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr)
1179{
1180 return fromJson<Type>(json.data(), json.size(), errors);
1181}
1182
1183} // namespace JsonReflector
1184} // namespace ReflectiveRapidJSON
1185
1186#endif // REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
Contains helper for error handling when deserializing JSON files.
RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
Parses the specified JSON string.
Definition reflector.h:73
Traits::Any< Traits::Not< Traits::IsComplete< Type > >, std::is_base_of< JsonSerializable< Type >, Type >, AdaptedJsonSerializable< Type > > IsJsonSerializable
Definition reflector.h:93
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
Serializes the specified reflectable.
Definition reflector.h:1086
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue< RAPIDJSON_NAMESPACE::UTF8< char > >::ConstObject &value, JsonDeserializationErrors *errors)
Pulls the reflectable which has a custom type from the specified object.
Traits::Any< std::is_integral< Type >, std::is_floating_point< Type >, std::is_pointer< Type >, std::is_enum< Type >, Traits::IsSpecializingAnyOf< Type, std::tuple, std::pair >, Traits::IsIteratable< Type >, Traits::IsSpecializingAnyOf< Type, std::unique_ptr, std::shared_ptr, std::weak_ptr, std::optional >, IsVariant< Type > > IsBuiltInType
Definition reflector.h:85
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors=nullptr)
Deserializes the specified JSON to.
Definition reflector.h:1098
constexpr RAPIDJSON_NAMESPACE::SizeType rapidJsonSize(std::size_t size)
Casts the specified size to the size type used by RapidJSON ensuring no overflow happens.
Definition reflector.h:53
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Pushes the specified reflectable to the specified value.
Definition reflector.h:140
RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
Serializes the specified JSON document.
Definition reflector.h:62
RAPIDJSON_NAMESPACE::Document toJsonDocument(const Type &reflectable)
Serializes the specified reflectable which has a custom type or can be mapped to and object.
Definition reflector.h:1019
Traits::Not< IsBuiltInType< Type > > IsCustomType
Definition reflector.h:88
Traits::All< Traits::IsSpecializationOf< Type, std::variant > > IsVariant
Definition traits.h:57
Traits::Any< Traits::IsSpecializationOf< Type, std::multimap >, Traits::IsSpecializationOf< Type, std::unordered_multimap >, TreatAsMultiMapOrHash< Type > > IsMultiMapOrHash
Definition traits.h:40
constexpr JsonType jsonType()
Traits::All< Traits::IsIteratable< Type >, Traits::Not< Traits::IsSpecializationOf< Type, std::basic_string > >, Traits::Not< IsMapOrHash< Type > >, Traits::Not< IsMultiMapOrHash< Type > >, Traits::Not< IsSet< Type > >, Traits::Not< IsMultiSet< Type > > > IsArray
Definition traits.h:52
Traits::Any< Traits::IsSpecializationOf< Type, std::map >, Traits::IsSpecializationOf< Type, std::unordered_map >, TreatAsMapOrHash< Type > > IsMapOrHash
Definition traits.h:38
The AdaptedJsonSerializable class allows considering 3rd party classes as serializable.
Definition reflector.h:40
static constexpr const char * name
Definition reflector.h:41
static constexpr const char * qualifiedName
Definition reflector.h:42
static constexpr std::size_t noIndex
Indicates no array was being processed when the error occurred.
The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType)
Reports a type mismatch between.
const char * currentMember
The name of the member (in currentRecord) which is currently being processed.
void reportArraySizeMismatch()
Reports an array size mismatch.
std::size_t currentIndex
The index in the array which is currently processed.
The TuplePullHelper class helps deserializing tuples from JSON arrays.
Definition reflector.h:793
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition reflector.h:794
The TuplePushHelper class helps serializing tuples to JSON arrays.
Definition reflector.h:279
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition reflector.h:280