Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
ObjectVariantMapper.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <algorithm>
5
8#include "Stroika/Foundation/Containers/Adapters/Adder.h"
13#if qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities
14#include "Stroika/Foundation/Execution/Activity.h"
15#endif
16#include "Stroika/Foundation/DataExchange/BadFormatException.h"
18#include "Stroika/Foundation/Execution/Throw.h"
20
21// Comment this in to turn on aggressive noisy DbgTrace in this module (note the extra long name since its in a header)
22//#define Stroika_Foundation_DataExchange_ObjectVariantMapper_USE_NOISY_TRACE_IN_THIS_MODULE_ 1
23
25
26 /*
27 ********************************************************************************
28 ************************** DefaultConstructForRead *****************************
29 ********************************************************************************
30 */
31 template <>
32 struct DefaultConstructForRead<Time::Date> {
33 constexpr Time::Date operator() () const
34 {
35 return Time::Date::kMin;
36 }
37 };
38 template <>
39 struct DefaultConstructForRead<Time::DateTime> {
40 constexpr Time::DateTime operator() () const
41 {
42 return Time::DateTime::kMin;
43 }
44 };
45 template <>
46 struct DefaultConstructForRead<Time::TimeOfDay> {
47 constexpr Time::TimeOfDay operator() () const
48 {
50 }
51 };
52 template <>
53 struct DefaultConstructForRead<IO::Network::CIDR> {
54 IO::Network::CIDR operator() () const
55 {
56 using namespace IO::Network;
57 return CIDR{InternetAddress{}, 0};
58 }
59 };
60
61 /*
62 ********************************************************************************
63 ******************** ObjectVariantMapper::StructFieldInfo **********************
64 ********************************************************************************
65 */
66 inline ObjectVariantMapper::StructFieldInfo::StructFieldInfo (const String& serializedFieldName, const StructFieldMetaInfo& fieldMetaInfo)
67 : StructFieldInfo{serializedFieldName, fieldMetaInfo, optional<TypeMappingDetails>{}}
68 {
69 }
70 inline ObjectVariantMapper::StructFieldInfo::StructFieldInfo (const String& serializedFieldName, const StructFieldMetaInfo& fieldMetaInfo,
71 const optional<TypeMappingDetails>& overrideTypeMapper)
72 : fSerializedFieldName_{serializedFieldName}
73 , fFieldMetaInfo_{fieldMetaInfo}
74 , fOverrideTypeMapper_{overrideTypeMapper}
75 {
76 Require (not serializedFieldName.empty ()); // Since Stroika v3.0d7
77 }
78
79 inline String ObjectVariantMapper::StructFieldInfo::GetSerializedFieldName () const
80 {
81 return fSerializedFieldName_;
82 }
83 inline StructFieldMetaInfo ObjectVariantMapper::StructFieldInfo::GetStructFieldMetaInfo () const
84 {
85 return *fFieldMetaInfo_;
86 }
87 inline auto ObjectVariantMapper::StructFieldInfo::GetOverrideTypeMapper () const -> optional<TypeMappingDetails>
88 {
89 return fOverrideTypeMapper_;
90 }
91 /*
92 ********************************************************************************
93 *********** DataExchange::ObjectVariantMapper::TypeMappingDetails **************
94 ********************************************************************************
95 */
97 const ToGenericObjectMapperType& toObjectMapper, const type_index& forTypeInfo)
98 : fForType_{forTypeInfo}
99 , fFromObjectMapper_{fromObjectMapper}
100 , fToObjectMapper_{toObjectMapper}
101 {
102 }
103 template <typename T>
104 inline ObjectVariantMapper::TypeMappingDetails::TypeMappingDetails (const FromObjectMapperType<T>& fromObjectMapper,
105 const ToObjectMapperType<T>& toObjectMapper, const type_index& forTypeInfo)
106 requires (not same_as<T, void>)
107 : TypeMappingDetails{mkGenericFromMapper_ (fromObjectMapper), mkGenericToMapper_ (toObjectMapper), forTypeInfo}
108 {
109 }
110 inline strong_ordering ObjectVariantMapper::TypeMappingDetails::operator<=> (const TypeMappingDetails& rhs) const
111 {
112 return Common::StdCompat::compare_three_way{}(fForType_, rhs.fForType_);
113 }
114 inline bool ObjectVariantMapper::TypeMappingDetails::operator== (const TypeMappingDetails& rhs) const
115 {
116 return fForType_ == rhs.fForType_; // just compare types, not functions
117 }
118 inline type_index ObjectVariantMapper::TypeMappingDetails::GetForType () const
119 {
120 return fForType_;
121 }
122 inline auto ObjectVariantMapper::TypeMappingDetails::GetGenericFromObjectMapper () const -> FromGenericObjectMapperType
123 {
124 return fFromObjectMapper_;
125 }
126 inline auto ObjectVariantMapper::TypeMappingDetails::GetGenericToObjectMapper () const -> ToGenericObjectMapperType
127 {
128 return fToObjectMapper_;
129 }
130 template <typename T>
131 inline ObjectVariantMapper::FromObjectMapperType<T> ObjectVariantMapper::TypeMappingDetails::FromObjectMapper (const FromGenericObjectMapperType& fromObjectMapper)
132 {
133 // See http://stroika-bugs.sophists.com/browse/STK-601 - properly/safely map the types, or do the more performant cast of the function objects
134 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
135 return [fromObjectMapper] (const ObjectVariantMapper& mapper, const T* objOfType) -> VariantValue {
136 return fromObjectMapper (mapper, objOfType);
137 };
138 }
139 else {
140 return *reinterpret_cast<const FromObjectMapperType<T>*> (&fromObjectMapper);
141 }
142 }
143 template <typename T>
144 inline ObjectVariantMapper::FromObjectMapperType<T> ObjectVariantMapper::TypeMappingDetails::FromObjectMapper () const
145 {
146 Require (type_index{typeid (T)} == fForType_);
147 return FromObjectMapper<T> (fFromObjectMapper_);
148 }
149 template <typename T>
150 inline ObjectVariantMapper::ToObjectMapperType<T> ObjectVariantMapper::TypeMappingDetails::ToObjectMapper (const ToGenericObjectMapperType& toObjectMapper)
151 {
152 // See http://stroika-bugs.sophists.com/browse/STK-601 - properly/safely map the types, or do the more performant cast of the function objects
153 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
154 return [toObjectMapper] (const ObjectVariantMapper& mapper, const VariantValue& d, T* into) -> void {
155 toObjectMapper (mapper, d, into);
156 };
157 }
158 else {
159 return *reinterpret_cast<const ToObjectMapperType<T>*> (&toObjectMapper);
160 }
161 }
162 template <typename T>
163 inline ObjectVariantMapper::ToObjectMapperType<T> ObjectVariantMapper::TypeMappingDetails::ToObjectMapper () const
164 {
165 Require (type_index{typeid (T)} == fForType_);
166 return ToObjectMapper<T> (fToObjectMapper_);
167 }
168 template <typename T>
170 ObjectVariantMapper::TypeMappingDetails::mkGenericFromMapper_ (const FromObjectMapperType<T>& fromObjectMapper)
171 {
172 // See http://stroika-bugs.sophists.com/browse/STK-601 - properly/safely map the types, or do the more performant cast of the function objects
173 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
174 return [fromObjectMapper] (const ObjectVariantMapper& mapper, const void* objOfType) -> VariantValue {
175 return fromObjectMapper (mapper, reinterpret_cast<const T*> (objOfType));
176 };
177 }
178 else {
179 return *reinterpret_cast<const FromGenericObjectMapperType*> (&fromObjectMapper);
180 }
181 }
182 template <typename T>
183 inline ObjectVariantMapper::ToGenericObjectMapperType ObjectVariantMapper::TypeMappingDetails::mkGenericToMapper_ (const ToObjectMapperType<T>& toObjectMapper)
184 {
185 if (Debug::kBuiltWithUndefinedBehaviorSanitizer) {
186 return [toObjectMapper] (const ObjectVariantMapper& mapper, const VariantValue& d, void* into) -> void {
187 toObjectMapper (mapper, d, reinterpret_cast<T*> (into));
188 };
189 }
190 else {
191 return *reinterpret_cast<const ToGenericObjectMapperType*> (&toObjectMapper);
192 }
193 }
194
195 /*
196 ********************************************************************************
197 ************** DataExchange::ObjectVariantMapper::TypesRegistry ****************
198 ********************************************************************************
199 */
200 inline ObjectVariantMapper::TypesRegistry::TypesRegistry (const Traversal::Iterable<TypeMappingDetails>& src)
201 : fSerializers_{src}
202 {
203 }
204 inline optional<ObjectVariantMapper::TypeMappingDetails> ObjectVariantMapper::TypesRegistry::Lookup (type_index t) const
205 {
206 return fSerializers_.Lookup (t);
207 }
208 inline void ObjectVariantMapper::TypesRegistry::Add (const TypeMappingDetails& typeMapDetails)
209 {
210 fSerializers_.Add (typeMapDetails);
211 }
212 inline void ObjectVariantMapper::TypesRegistry::Add (const Traversal::Iterable<TypeMappingDetails>& typeMapDetails)
213 {
214 fSerializers_ += typeMapDetails;
215 }
216 inline void ObjectVariantMapper::TypesRegistry::operator+= (const TypeMappingDetails& typeMapDetails)
217 {
218 Add (typeMapDetails);
219 }
220 inline void ObjectVariantMapper::TypesRegistry::operator+= (const Traversal::Iterable<TypeMappingDetails>& typeMapDetails)
221 {
222 Add (typeMapDetails);
223 }
224 inline Traversal::Iterable<ObjectVariantMapper::TypeMappingDetails> ObjectVariantMapper::TypesRegistry::GetMappers () const
225 {
226 return fSerializers_;
227 }
228
229 /*
230 ********************************************************************************
231 ******************************** ObjectVariantMapper ***************************
232 ********************************************************************************
233 */
234 template <Common::StdCompat::formattable<wchar_t> T>
235 inline const ObjectVariantMapper::FromObjectMapperType<T> ObjectVariantMapper::kTraceFromObjectMapper =
236 [] (const ObjectVariantMapper& mapper, const T* objOfType) -> VariantValue {
237 DbgTrace ("FromObject<{}>(mapper, {}) called", typeid (T), objOfType);
238 return {};
239 };
240 template <Common::StdCompat::formattable<wchar_t> T>
241 inline const ObjectVariantMapper::ToObjectMapperType<T> ObjectVariantMapper::kTraceToObjectMapper =
242 [] (const ObjectVariantMapper& mapper, const VariantValue& d, T* into) -> void {
243 DbgTrace ("ToObject<{}>(mapper, {}, {}) called", typeid (T), d, into);
244 };
245 inline ObjectVariantMapper::TypesRegistry ObjectVariantMapper::GetTypeMappingRegistry () const
246 {
247 return fTypeMappingRegistry_;
248 }
249 inline void ObjectVariantMapper::SetTypeMappingRegistry (const TypesRegistry& s)
250 {
251 fTypeMappingRegistry_ = s;
252 }
253 template <typename T>
254 inline void ObjectVariantMapper::Add (const FromObjectMapperType<T>& fromObjectMapper, const ToObjectMapperType<T>& toObjectMapper)
255 {
256 Add (TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (T)});
257 }
259 {
260 Add (rhs);
261 }
263 {
264 Add (rhs);
265 }
266 inline void ObjectVariantMapper::operator+= (const TypesRegistry& rhs)
267 {
268 Add (rhs);
269 }
271 {
272 Add (rhs);
273 }
274 template <typename T, typename... ARGS>
275 inline void ObjectVariantMapper::AddCommonType (ARGS&&... args)
276 {
277 if constexpr (same_as<T, TypedBLOB>) {
278 // pre-add dependent types...
279 AddCommonType<Memory::BLOB> ();
280 //AddCommonType<InternetMediaType> (); --already in by default
281 }
282 const T* n = nullptr; // arg unused, just for overloading
283 AssertDependentTypesAlreadyInRegistry_ (n);
284 auto&& serializer = MakeCommonSerializer<T> (forward<ARGS> (args)...);
285 Assert (serializer.GetForType () == typeid (T));
286 Add (serializer);
287 }
288 template <typename CLASS>
289 inline void ObjectVariantMapper::AddClass (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions, const ClassMapperOptions<CLASS>& mapperOptions)
290 {
291 Add (MakeClassSerializer_<CLASS> (fieldDescriptions, mapperOptions, this));
292 }
293 template <typename CLASS, typename BASE_CLASS>
294 void ObjectVariantMapper::AddSubClass (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions, const ClassMapperOptions<CLASS>& mapperOptions)
295 {
296 TypeMappingDetails baseClassTypeMapper = Lookup_ (typeid (BASE_CLASS));
297 ClassMapperOptions<CLASS> useOptions = mapperOptions;
298 Require (useOptions.fBeforeFrom == nullptr);
299 Require (useOptions.fBeforeTo == nullptr);
300 // subtle, but OK - function taking ptr to BASE_CLASS can be used as a function ptr taking SUBCLASS (since ptr always satisfies rule is base_class)
301 useOptions.fBeforeFrom = baseClassTypeMapper.FromObjectMapper<BASE_CLASS> ();
302 useOptions.fBeforeTo = baseClassTypeMapper.ToObjectMapper<BASE_CLASS> ();
303 Add (MakeClassSerializer_<CLASS> (fieldDescriptions, useOptions, this));
304 }
305 template <typename T>
307 {
308 Require (Lookup_ (typeid (T)).GetGenericToObjectMapper ());
309 return Lookup_ (typeid (T)).ToObjectMapper<T> ();
310 }
311 template <typename T>
313 {
314 return Lookup_ (typeid (T)).FromObjectMapper<T> ();
315 }
316 template <typename T>
317 inline void ObjectVariantMapper::ToObject (const ToObjectMapperType<T>& toObjectMapper, const VariantValue& v, T* into) const
318 {
319 RequireNotNull (into);
320 // if toObjectMapper, this does nothing to into
321 // LOGICALLY require but cannot compare == on std::function! Require (toObjectMapper == ToObjectMapper<T> ()); // pass it in as optimization, but not change of semantics
322 if (toObjectMapper != nullptr) {
323 toObjectMapper (*this, v, into);
324 }
325 }
326 template <typename T>
327 inline void ObjectVariantMapper::ToObject (const VariantValue& v, T* into) const
328 {
329 RequireNotNull (into);
330 ToObject<T> (ToObjectMapper<T> (), v, into);
331 }
332 template <IDefaultConstructForRead T>
333 inline T ObjectVariantMapper::ToObject (const ToObjectMapperType<T>& toObjectMapper, const VariantValue& v) const
334 {
335 T tmp = DefaultConstructForRead<T>{}();
336 ToObject (toObjectMapper, v, &tmp);
337 return tmp;
338 }
339 template <IDefaultConstructForRead T>
340 inline T ObjectVariantMapper::ToObject (const VariantValue& v) const
341 {
342 return ToObject<T> (ToObjectMapper<T> (), v);
343 }
344 template <typename T>
345 inline optional<T> ObjectVariantMapper::ToObjectQuietly (const VariantValue& v) const
346 {
347 try {
348 return ToObject<T> (ToObjectMapper<T> (), v);
349 }
350 catch (...) {
351 return nullopt;
352 }
353 }
354 template <typename T>
355 inline VariantValue ObjectVariantMapper::FromObject (const FromObjectMapperType<T>& fromObjectMapper, const T& from) const
356 {
357 // define null fromObjectMapper as just retuning a null variant value
358 if (fromObjectMapper == nullptr) {
359 return VariantValue{};
360 }
361 // LOGICALLY require but cannot compare == on std::function! Require (fromObjectMapper == FromObjectMapper<T> ()); // pass it in as optimization, but not change of semantics
362 return fromObjectMapper (*this, &from);
363 }
364 template <typename T>
365 inline VariantValue ObjectVariantMapper::FromObject (const T& from) const
366 {
367 return FromObjectMapper<T> () (*this, &from);
368 }
369 template <typename T>
370 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (T*)
371 {
372 // by default nothing to check, just check certain partial specializations
373 }
374 template <typename T>
375 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (optional<T>*)
376 {
378 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
379 }
380 }
381 template <typename DOMAIN_TYPE, typename RANGE_TYPE>
382 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Containers::Bijection<DOMAIN_TYPE, RANGE_TYPE>*)
383 {
385 (void)Lookup_ (typeid (DOMAIN_TYPE)); // just for side-effect of assert check
386 (void)Lookup_ (typeid (RANGE_TYPE)); // just for side-effect of assert check
387 }
388 }
389 template <typename T>
390 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (Containers::Collection<T>*)
391 {
393 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
394 }
395 }
396 template <typename T, typename TRAITS>
397 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Traversal::DiscreteRange<T, TRAITS>*)
398 {
400 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
401 }
402 }
403 template <typename T, typename KEY_TYPE, typename TRAITS>
404 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (Containers::KeyedCollection<T, KEY_TYPE, TRAITS>*)
405 {
407 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
408 (void)Lookup_ (typeid (KEY_TYPE)); // just for side-effect of assert check
409 }
410 }
411 template <typename KEY_TYPE, typename VALUE_TYPE>
412 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Mapping<KEY_TYPE, VALUE_TYPE>*)
413 {
415 (void)Lookup_ (typeid (KEY_TYPE)); // just for side-effect of assert check
416 (void)Lookup_ (typeid (VALUE_TYPE)); // just for side-effect of assert check
417 }
418 }
419 template <typename T, typename TRAITS>
420 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Traversal::Range<T, TRAITS>*)
421 {
423 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
424 }
425 }
426 template <typename T>
427 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Sequence<T>*)
428 {
430 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
431 }
432 }
433 template <typename T>
434 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Set<T>*)
435 {
437 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
438 }
439 }
440 template <typename T, typename TRAITS>
441 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Execution::Synchronized<T, TRAITS>*)
442 {
444 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
445 }
446 }
447 template <typename T>
448 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const vector<T>*)
449 {
451 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
452 }
453 }
454 template <typename T1, typename T2>
455 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const pair<T1, T2>*)
456 {
458 (void)Lookup_ (typeid (T1)); // just for side-effect of assert check
459 (void)Lookup_ (typeid (T2)); // just for side-effect of assert check
460 }
461 }
462 template <typename T>
463 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Common::CountedValue<T>*)
464 {
465#if qStroika_Foundation_Debug_AssertionsChecked
466 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
467#endif
468 }
469 template <typename T1, typename T2>
470 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const Common::KeyValuePair<T1, T2>*)
471 {
473 (void)Lookup_ (typeid (T1)); // just for side-effect of assert check
474 (void)Lookup_ (typeid (T2)); // just for side-effect of assert check
475 }
476 }
477 template <typename T1>
478 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const tuple<T1>*)
479 {
481 (void)Lookup_ (typeid (T1)); // just for side-effect of assert check
482 }
483 }
484 template <typename T1, typename T2>
485 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const tuple<T1, T2>*)
486 {
488 (void)Lookup_ (typeid (T1)); // just for side-effect of assert check
489 (void)Lookup_ (typeid (T2)); // just for side-effect of assert check
490 }
491 }
492 template <typename T1, typename T2, typename T3>
493 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const tuple<T1, T2, T3>*)
494 {
496 (void)Lookup_ (typeid (T1)); // just for side-effect of assert check
497 (void)Lookup_ (typeid (T2)); // just for side-effect of assert check
498 (void)Lookup_ (typeid (T3)); // just for side-effect of assert check
499 }
500 }
501 template <typename T, size_t SZ>
502 inline void ObjectVariantMapper::AssertDependentTypesAlreadyInRegistry_ (const T (*)[SZ])
503 {
505 (void)Lookup_ (typeid (T)); // just for side-effect of assert check
506 }
507 }
508 template <Containers::Adapters::IAddableTo ACTUAL_CONTAINER_TYPE>
510 {
511 using namespace Characters::Literals;
512 using T = typename ACTUAL_CONTAINER_TYPE::value_type;
513 FromObjectMapperType<ACTUAL_CONTAINER_TYPE> fromObjectMapper = [] (const ObjectVariantMapper& mapper,
514 const ACTUAL_CONTAINER_TYPE* fromObjOfTypeT) -> VariantValue {
515 RequireNotNull (fromObjOfTypeT);
517 if (not fromObjOfTypeT->empty ()) {
518 FromObjectMapperType<T> valueMapper{mapper.FromObjectMapper<T> ()};
519 for (const auto& i : *fromObjOfTypeT) {
520 s.Append (mapper.FromObject<T> (valueMapper, i));
521 }
522 }
523 return VariantValue{s};
524 };
525 ToObjectMapperType<ACTUAL_CONTAINER_TYPE> toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d,
526 ACTUAL_CONTAINER_TYPE* intoObjOfTypeT) -> void {
527 RequireNotNull (intoObjOfTypeT);
528 Require (intoObjOfTypeT->empty ());
529#if qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities
530 auto decodingClassActivity = Execution::LazyEvalActivity{
531 [&] () -> String { return "Decoding {:.100} into class {}"_f(d, type_index{typeid (ACTUAL_CONTAINER_TYPE)}); }};
532 Execution::DeclareActivity da{&decodingClassActivity};
533#endif
535 if (not s.empty ()) {
536 ToObjectMapperType<T> valueMapper{mapper.ToObjectMapper<T> ()};
537 for (const auto& i : s) {
538 Containers::Adapters::Adder<ACTUAL_CONTAINER_TYPE>::Add (intoObjOfTypeT, mapper.ToObject<T> (valueMapper, i));
539 }
540 }
541 };
542 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (ACTUAL_CONTAINER_TYPE)};
543 }
544 template <typename T, typename... ARGS>
545 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer (ARGS&&... args)
546 {
547 const T* n = nullptr; // arg unused, just for overloading
548 TypeMappingDetails tmp{MakeCommonSerializer_ (n, forward<ARGS> (args)...)};
549 // NB: because of how we match on MakeCommonSerializer_, the type it sees maybe a base class of T, and we want to actually register the type the user specified.
550 return TypeMappingDetails{tmp.GetGenericFromObjectMapper (), tmp.GetGenericToObjectMapper (), typeid (T)};
551 }
552 template <typename T>
554 const ClassMapperOptions<T>& options)
555 requires (is_class_v<T>)
556 {
557 return MakeClassSerializer_<T> (fieldDescriptions, options, nullptr);
558 }
559 template <typename T>
560 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeClassSerializer_ (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions,
561 const ClassMapperOptions<T>& options,
562 const ObjectVariantMapper* mapperToCheckAgainst)
563 requires (is_class_v<T>)
564 {
565 return MakeCommonSerializer_ForClassObject_and_check_<T> (typeid (T), sizeof (T), fieldDescriptions, options, mapperToCheckAgainst);
566 }
567 template <typename T>
568 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Math::CommonStatistics<T>*)
569 {
570 return MakeClassSerializer_<Math::CommonStatistics<T>> (
571 {
574 {"mean"sv, &Math::CommonStatistics<T>::fMean},
575 {"median"sv, &Math::CommonStatistics<T>::fMedian},
576 {"stddev"sv, &Math::CommonStatistics<T>::fStandardDeviation},
577 },
578 ClassMapperOptions<Math::CommonStatistics<T>>{}, nullptr);
579 }
580 template <typename DOMAIN_TYPE, typename RANGE_TYPE>
581 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::Bijection<DOMAIN_TYPE, RANGE_TYPE>*)
582 {
583 using namespace Characters;
584 using Containers::Bijection;
585 FromObjectMapperType<Bijection<DOMAIN_TYPE, RANGE_TYPE>> fromObjectMapper =
586 [] (const ObjectVariantMapper& mapper, const Bijection<DOMAIN_TYPE, RANGE_TYPE>* fromObjOfTypeT) -> VariantValue {
587 RequireNotNull (fromObjOfTypeT);
588 FromObjectMapperType<DOMAIN_TYPE> domainMapper{mapper.FromObjectMapper<DOMAIN_TYPE> ()};
589 FromObjectMapperType<RANGE_TYPE> rangeMapper{mapper.FromObjectMapper<RANGE_TYPE> ()};
590 Sequence<VariantValue> s;
591 for (const auto& i : *fromObjOfTypeT) {
592 Sequence<VariantValue> encodedPair;
593 encodedPair.Append (mapper.FromObject<DOMAIN_TYPE> (domainMapper, i.first));
594 encodedPair.Append (mapper.FromObject<RANGE_TYPE> (rangeMapper, i.second));
595 s.Append (VariantValue{encodedPair});
596 }
597 return VariantValue{s};
598 };
599 ToObjectMapperType<Bijection<DOMAIN_TYPE, RANGE_TYPE>> toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d,
600 Bijection<DOMAIN_TYPE, RANGE_TYPE>* intoObjOfTypeT) -> void {
601 RequireNotNull (intoObjOfTypeT);
602 ToObjectMapperType<DOMAIN_TYPE> domainMapper{mapper.ToObjectMapper<DOMAIN_TYPE> ()};
603 ToObjectMapperType<RANGE_TYPE> rangeMapper{mapper.ToObjectMapper<RANGE_TYPE> ()};
604 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
605 intoObjOfTypeT->clear ();
606 for (const VariantValue& encodedPair : s) {
607 Sequence<VariantValue> p = encodedPair.As<Sequence<VariantValue>> ();
608 if (p.size () != 2) [[unlikely]] {
609 DbgTrace ("Bijection ('{}') element with item count ({}) other than 2"_f,
610 type_index{typeid (Bijection<DOMAIN_TYPE, RANGE_TYPE>)}, static_cast<int> (p.size ()));
611 static const auto kException_ = BadFormatException{"Mapping element with item count other than 2"sv};
612 Execution::Throw (kException_);
613 }
614 intoObjOfTypeT->Add (mapper.ToObject<DOMAIN_TYPE> (domainMapper, p[0]), mapper.ToObject<RANGE_TYPE> (rangeMapper, p[1]));
615 }
616 };
617 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (Bijection<DOMAIN_TYPE, RANGE_TYPE>)};
618 }
619 template <typename T>
620 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::Collection<T>*)
621 {
622 return MakeCommonSerializer_WithAdder<Containers::Collection<T>> ();
623 }
624 template <typename T, typename KEY_TYPE, typename TRAITS>
625 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::KeyedCollection<T, KEY_TYPE, TRAITS>*)
626 {
627 return MakeCommonSerializer_WithAdder<Containers::KeyedCollection<T, KEY_TYPE, TRAITS>> ();
628 }
629 template <typename KEY_TYPE, typename VALUE_TYPE>
630 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Mapping<KEY_TYPE, VALUE_TYPE>*)
631 {
632 // NB: We default to 'json object/mapping' because this is the overwhelmingly most commonly expected mapping (especially to JSON), but
633 // MakeCommonSerializer_MappingAsArrayOfKeyValuePairs is more general. If KEY_TYPE is not convertible to a string, or you wish to strucutre
634 // the VariantValue (typically think JSON representation) as an array of Key/Value pairs, then use MakeCommonSerializer_MappingAsArrayOfKeyValuePairs
635 return MakeCommonSerializer_MappingWithStringishKey<Containers::Mapping<KEY_TYPE, VALUE_TYPE>> ();
636 }
637 template <typename T>
638 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::MultiSet<T>*)
639 {
640 return MakeCommonSerializer_WithAdder<Containers::MultiSet<T>> ();
641 }
642 template <typename T>
643 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const optional<T>*)
644 {
645 FromObjectMapperType<optional<T>> fromObjectMapper = [] (const ObjectVariantMapper& mapper, const optional<T>* fromObjOfTypeT) -> VariantValue {
646 RequireNotNull (fromObjOfTypeT);
647 if (fromObjOfTypeT->has_value ()) {
648 return mapper.FromObject<T> (**fromObjOfTypeT);
649 }
650 else {
651 return VariantValue{};
652 }
653 };
654 ToObjectMapperType<optional<T>> toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d, optional<T>* intoObjOfTypeT) -> void {
655 RequireNotNull (intoObjOfTypeT);
656 if (d.GetType () == VariantValue::eNull) {
657 *intoObjOfTypeT = nullopt;
658 }
659 else {
660 // SEE http://stroika-bugs.sophists.com/browse/STK-910
661 // fix here - I KNOW I have something there, but how to construct
662 *intoObjOfTypeT = mapper.ToObject<T> (d);
663 }
664 };
665 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (optional<T>)};
666 }
667 template <typename T>
668 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const optional<T>*, const OptionalSerializerOptions& options)
669 {
670 if (not options.fTMapper.has_value ()) {
671 return MakeCommonSerializer_ ((const optional<T>*)nullptr);
672 }
673 FromObjectMapperType<optional<T>> fromObjectMapper = [options] (const ObjectVariantMapper& mapper, const optional<T>* fromObjOfTypeT) -> VariantValue {
674 RequireNotNull (fromObjOfTypeT);
675 if (fromObjOfTypeT->has_value ()) {
676 return options.fTMapper->FromObjectMapper<T> () (mapper, &**fromObjOfTypeT);
677 }
678 else {
679 return VariantValue{};
680 }
681 };
682 ToObjectMapperType<optional<T>> toObjectMapper = [options] (const ObjectVariantMapper& mapper, const VariantValue& d,
683 optional<T>* intoObjOfTypeT) -> void {
684 RequireNotNull (intoObjOfTypeT);
685 if (d.GetType () == VariantValue::eNull) {
686 *intoObjOfTypeT = nullopt;
687 }
688 else {
689 // SEE http://stroika-bugs.sophists.com/browse/STK-910
690 // fix here - I KNOW I have something there, but how to construct
691 T tmp{};
692 options.fTMapper->ToObjectMapper<T> () (mapper, d, &tmp);
693 *intoObjOfTypeT = tmp;
694 }
695 };
696 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (optional<T>)};
697 }
698 // http://stroika-bugs.sophists.com/browse/STK-910
699 template <>
700 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const optional<IO::Network::CIDR>*);
701 template <typename T, typename TRAITS>
702 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Execution::Synchronized<T, TRAITS>*)
703 {
704 using Execution::Synchronized;
705 auto fromObjectMapper = [] (const ObjectVariantMapper& mapper, const Synchronized<T, TRAITS>* fromObjOfTypeT) -> VariantValue {
706 RequireNotNull (fromObjOfTypeT);
707 return mapper.FromObject<T> (**fromObjOfTypeT);
708 };
709 auto toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d, Synchronized<T, TRAITS>* intoObjOfTypeT) -> void {
710 RequireNotNull (intoObjOfTypeT);
711 *intoObjOfTypeT = mapper.ToObject<T> (d);
712 };
713 return TypeMappingDetails{typeid (Synchronized<T, TRAITS>), fromObjectMapper, toObjectMapper};
714 }
715 template <typename T>
716 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Sequence<T>*)
717 {
718 return MakeCommonSerializer_WithAdder<Sequence<T>> ();
719 }
720 template <typename T>
721 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const vector<T>*)
722 {
723 return MakeCommonSerializer_WithAdder<vector<T>> ();
724 }
725 template <typename T1, typename T2>
726 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const pair<T1, T2>*)
727 {
728 // render as array of two elements
729 return TypeMappingDetails{
730 FromObjectMapperType<pair<T1, T2>>{[] (const ObjectVariantMapper& mapper, const pair<T1, T2>* fromObj) -> VariantValue {
731 return VariantValue{Sequence<VariantValue>{mapper.FromObject<T1> (fromObj->first), mapper.FromObject<T2> (fromObj->second)}};
732 }},
733 ToObjectMapperType<pair<T1, T2>>{[] (const ObjectVariantMapper& mapper, const VariantValue& d, pair<T1, T2>* intoObj) -> void {
734 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
735 if (s.size () < 2) {
736 static const auto kException_ = BadFormatException{"Array size out of range for pair"sv};
737 Execution::Throw (kException_);
738 };
739 *intoObj = make_pair (mapper.ToObject<T1> (s[0]), mapper.ToObject<T2> (s[1]));
740 }},
741 typeid (pair<T1, T2>)};
742 }
743 template <typename T>
744 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Common::CountedValue<T>*)
745 {
746 // render as array of two elements
747 using CountedValue = typename Common::CountedValue<T>;
748 using CounterType = typename CountedValue::CounterType;
749 return TypeMappingDetails{
750 FromObjectMapperType<CountedValue>{[] (const ObjectVariantMapper& mapper, const CountedValue* fromObj) -> VariantValue {
751 return VariantValue{Sequence<VariantValue>{mapper.FromObject<T> (fromObj->fValue), mapper.FromObject<CounterType> (fromObj->fCount)}};
752 }},
753 ToObjectMapperType<CountedValue>{[] (const ObjectVariantMapper& mapper, const VariantValue& d, CountedValue* intoObj) -> void {
754 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
755 if (s.size () < 2) {
756 static const auto kException_ = BadFormatException{"Array size out of range for CountedValue"sv};
757 Execution::Throw (kException_);
758 };
759 *intoObj = CountedValue{mapper.ToObject<T> (s[0]), mapper.ToObject<CounterType> (s[1])};
760 }},
761 typeid (CountedValue)};
762 }
763 template <typename T1, typename T2>
764 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Common::KeyValuePair<T1, T2>*)
765 {
766 // render as array of two elements
767 return TypeMappingDetails{
768 FromObjectMapperType<Common::KeyValuePair<T1, T2>>{[] (const ObjectVariantMapper& mapper, const Common::KeyValuePair<T1, T2>* fromObj) -> VariantValue {
769 return VariantValue{Sequence<VariantValue>{mapper.FromObject<T1> (fromObj->fKey), mapper.FromObject<T2> (fromObj->fValue)}};
770 }},
771 ToObjectMapperType<Common::KeyValuePair<T1, T2>>{
772 [] (const ObjectVariantMapper& mapper, const VariantValue& d, Common::KeyValuePair<T1, T2>* intoObj) -> void {
773 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
774 if (s.size () < 2) {
775 static const auto kException_ = BadFormatException{"Array size out of range for KeyValuePair"sv};
776 Execution::Throw (kException_);
777 };
778 *intoObj = Common::KeyValuePair<T1, T2>{mapper.ToObject<T1> (s[0]), mapper.ToObject<T2> (s[1])};
779 }},
780 typeid (Common::KeyValuePair<T1, T2>)};
781 }
782 template <typename T1>
783 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const tuple<T1>*)
784 {
785 // render as array of one element
786 return TypeMappingDetails{FromObjectMapperType<tuple<T1>>{[] (const ObjectVariantMapper& mapper, const tuple<T1>* fromObj) -> VariantValue {
787 return VariantValue{Sequence<VariantValue>{mapper.FromObject<T1> (std::get<0> (*fromObj))}};
788 }},
789 ToObjectMapperType<tuple<T1>>{[] (const ObjectVariantMapper& mapper, const VariantValue& d, tuple<T1>* intoObj) -> void {
790 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
791 if (s.size () < 1) {
792 static const auto kException_ = BadFormatException{"Array size out of range for tuple/1"sv};
793 Execution::Throw (kException_);
794 };
795 *intoObj = make_tuple (mapper.ToObject<T1> (s[0]));
796 }},
797 typeid (tuple<T1>)};
798 }
799 template <typename T1, typename T2>
800 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const tuple<T1, T2>*)
801 {
802 // render as array of two elements
803 return TypeMappingDetails{
804 FromObjectMapperType<tuple<T1, T2>>{[] (const ObjectVariantMapper& mapper, const tuple<T1, T2>* fromObj) -> VariantValue {
805 return VariantValue{
806 Sequence<VariantValue>{mapper.FromObject<T1> (std::get<0> (*fromObj)), mapper.FromObject<T2> (std::get<1> (*fromObj))}};
807 }},
808 ToObjectMapperType<tuple<T1, T2>>{[] (const ObjectVariantMapper& mapper, const VariantValue& d, tuple<T1, T2>* intoObj) -> void {
809 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
810 if (s.size () < 2) {
811 static const auto kException_ = BadFormatException{"Array size out of range for tuple/2"sv};
812 Execution::Throw (kException_);
813 };
814 *intoObj = make_tuple (mapper.ToObject<T1> (s[0]), mapper.ToObject<T2> (s[1]));
815 }},
816 typeid (tuple<T1, T2>)};
817 }
818 template <typename T1, typename T2, typename T3>
819 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const tuple<T1, T2, T3>*)
820 {
821 // render as array of three elements
822 return TypeMappingDetails{
823 FromObjectMapperType<tuple<T1, T2, T3>>{[] (const ObjectVariantMapper& mapper, const tuple<T1, T2, T3>* fromObj) -> VariantValue {
824 return VariantValue{Sequence<VariantValue>{mapper.FromObject<T1> (std::get<0> (*fromObj)), mapper.FromObject<T2> (std::get<1> (*fromObj)),
825 mapper.FromObject<T3> (std::get<2> (*fromObj))}};
826 }},
827 ToObjectMapperType<tuple<T1, T2, T3>>{[] (const ObjectVariantMapper& mapper, const VariantValue& d, tuple<T1, T2, T3>* intoObj) -> void {
828 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
829 if (s.size () < 3) {
830 static const auto kException_ = BadFormatException{"Array size out of range for tuple/3"sv};
831 Execution::Throw (kException_);
832 };
833 *intoObj = make_tuple (mapper.ToObject<T1> (s[0]), mapper.ToObject<T2> (s[1]), mapper.ToObject<T3> (s[2]));
834 }},
835 typeid (tuple<T1, T2, T3>)};
836 }
837 template <typename T>
838 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Set<T>*)
839 {
840 return MakeCommonSerializer_WithAdder<Set<T>> ();
841 }
842 template <typename T>
843 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::SortedCollection<T>*)
844 {
845 return MakeCommonSerializer_WithAdder<Containers::SortedCollection<T>> ();
846 }
847 template <typename T, typename KEY_TYPE, typename TRAITS>
848 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::SortedKeyedCollection<T, KEY_TYPE, TRAITS>*)
849 {
850 return MakeCommonSerializer_WithAdder<Containers::SortedKeyedCollection<T, KEY_TYPE, TRAITS>> ();
851 }
852 template <typename KEY_TYPE, typename VALUE_TYPE>
853 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::SortedMapping<KEY_TYPE, VALUE_TYPE>*)
854 {
855 // NB: We default to 'json object/mapping' because this is the overwhelmingly most commonly expected mapping (especially to JSON), but
856 // MakeCommonSerializer_MappingAsArrayOfKeyValuePairs is more general. If KEY_TYPE is not convertible to a string, or you wish to strucutre
857 // the VariantValue (typically think JSON representation) as an array of Key/Value pairs, then use MakeCommonSerializer_MappingAsArrayOfKeyValuePairs
858 return MakeCommonSerializer_MappingWithStringishKey<Containers::SortedMapping<KEY_TYPE, VALUE_TYPE>> ();
859 }
860 template <typename T>
861 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::SortedMultiSet<T>*)
862 {
863 return MakeCommonSerializer_WithAdder<Containers::SortedMultiSet<T>> ();
864 }
865 template <typename T>
866 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Containers::SortedSet<T>*)
867 {
868 return MakeCommonSerializer_WithAdder<Containers::SortedSet<T>> ();
869 }
870 template <typename T, typename TRAITS>
871 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Traversal::DiscreteRange<T, TRAITS>*)
872 {
873 return MakeCommonSerializer_Range_<Traversal::DiscreteRange<T, TRAITS>> ();
874 }
875 template <typename T, typename TRAITS, typename... ARGS>
876 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const Traversal::Range<T, TRAITS>*, ARGS&&... args)
877 {
878 return MakeCommonSerializer_Range_<Traversal::Range<T, TRAITS>> (forward<ARGS> (args)...);
879 }
880 template <typename T>
881 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const T*)
882 requires (is_enum_v<T>)
883 {
884 return MakeCommonSerializer_NamedEnumerations<T> ();
885 }
886 template <typename T, size_t SZ>
887 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_ (const T (*)[SZ])
888 {
889 using namespace Characters::Literals;
890 // @todo - see http://stroika-bugs.sophists.com/browse/STK-581 - to switch from generic to 'T' based mapper.
891 auto fromObjectMapper = [] (const ObjectVariantMapper& mapper, const void* fromObjOfTypeT) -> VariantValue {
892 RequireNotNull (fromObjOfTypeT);
893 FromObjectMapperType<T> valueMapper{mapper.FromObjectMapper<T> ()}; // optimization if > 1 array elt, and anti-optimization array.size == 0
894 Sequence<VariantValue> s;
895 const T* actualMember{reinterpret_cast<const T*> (fromObjOfTypeT)};
896 for (auto i = actualMember; i < actualMember + SZ; ++i) {
897 s.Append (mapper.FromObject<T> (valueMapper, *i));
898 }
899 return VariantValue{s};
900 };
901 auto toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d, void* intoObjOfTypeT) -> void {
902 RequireNotNull (intoObjOfTypeT);
903 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
904 T* actualMember{reinterpret_cast<T*> (intoObjOfTypeT)};
905 if (s.size () > SZ) [[unlikely]] {
906 DbgTrace ("Array ('{}') actual size {} out of range"_f, type_index{typeid (T[SZ])}, static_cast<int> (s.size ()));
907 static const auto kException_ = BadFormatException{"Array size out of range"sv};
908 Execution::Throw (kException_);
909 }
910 ToObjectMapperType<T> valueMapper{mapper.ToObjectMapper<T> ()}; // optimization if > 1 array elt, and anti-optimization array.size == 0
911 size_t idx = 0;
912 for (const auto& i : s) {
913 actualMember[idx++] = mapper.ToObject<T> (valueMapper, i);
914 }
915 while (idx < SZ) {
916 actualMember[idx++] = T{};
917 }
918 };
919 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (T[SZ])};
920 }
921 template <typename KEY_TYPE, typename VALUE_TYPE, typename ACTUAL_CONTAINER_TYPE>
922 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_WithKeyValuePairAdd_ ()
923 {
924 auto fromObjectMapper = [] (const ObjectVariantMapper& mapper, const ACTUAL_CONTAINER_TYPE* fromObjOfTypeT) -> VariantValue {
925 RequireNotNull (fromObjOfTypeT);
926 FromObjectMapperType<KEY_TYPE> keyMapper{mapper.FromObjectMapper<KEY_TYPE> ()};
927 FromObjectMapperType<VALUE_TYPE> valueMapper{mapper.FromObjectMapper<VALUE_TYPE> ()};
928 Sequence<VariantValue> s;
929 for (const auto& i : *fromObjOfTypeT) {
930 Sequence<VariantValue> encodedPair;
931 encodedPair.Append (mapper.FromObject<KEY_TYPE> (keyMapper, i.fKey));
932 encodedPair.Append (mapper.FromObject<VALUE_TYPE> (valueMapper, i.fValue));
933 s.Append (VariantValue{encodedPair});
934 }
935 return VariantValue{s};
936 };
937 auto toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d, ACTUAL_CONTAINER_TYPE* intoObjOfTypeT) -> void {
938 RequireNotNull (intoObjOfTypeT);
939 /*
940 * NB: When you mixup having an array and an object (say because of writing with
941 * MakeCommonSerializer_ContainerWithStringishKey and reading back with this regular Mapping serializer?) or for other reasons,
942 * the covnersion to d.As<Sequence<VariantValue>> () can fail with a format exception.
943 *
944 * This requires you wrote with the above serializer.
945 */
946 ToObjectMapperType<KEY_TYPE> keyMapper{mapper.ToObjectMapper<KEY_TYPE> ()};
947 ToObjectMapperType<VALUE_TYPE> valueMapper{mapper.ToObjectMapper<VALUE_TYPE> ()};
948 Sequence<VariantValue> s = d.As<Sequence<VariantValue>> ();
949 intoObjOfTypeT->clear ();
950 for (const VariantValue& encodedPair : s) {
951 Sequence<VariantValue> p = encodedPair.As<Sequence<VariantValue>> ();
952 if (p.size () != 2) [[unlikely]] {
953 using namespace Characters;
954 DbgTrace ("Container with Key/Value pair ('{}') element with item count ({}) other than 2"_f,
955 type_index{typeid (ACTUAL_CONTAINER_TYPE)}, static_cast<int> (p.size ()));
956 static const auto kException_ = BadFormatException{"Container with Key/Value pair element with item count other than 2"_k};
957 Execution::Throw (kException_);
958 }
959 intoObjOfTypeT->Add (mapper.ToObject<KEY_TYPE> (keyMapper, p[0]), mapper.ToObject<VALUE_TYPE> (valueMapper, p[1]));
960 }
961 };
962 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (ACTUAL_CONTAINER_TYPE)};
963 }
964 template <typename ENUM_TYPE>
965 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_NamedEnumerations (const Containers::Bijection<ENUM_TYPE, String>& nameMap)
966 {
967 using namespace Characters::Literals;
968 static_assert (is_enum_v<ENUM_TYPE>, "MakeCommonSerializer_NamedEnumerations only works for enum types");
969 using SerializeAsType = typename underlying_type<ENUM_TYPE>::type;
970 static_assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE), "underlyingtype?");
971 FromObjectMapperType<ENUM_TYPE> fromObjectMapper = [nameMap] ([[maybe_unused]] const ObjectVariantMapper& mapper,
972 const ENUM_TYPE* fromObjOfTypeT) -> VariantValue {
973 RequireNotNull (fromObjOfTypeT);
974 Assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE));
975 Assert (static_cast<ENUM_TYPE> (static_cast<SerializeAsType> (*fromObjOfTypeT)) == *fromObjOfTypeT); // no round-trip loss
976 return VariantValue{*nameMap.Lookup (*fromObjOfTypeT)};
977 };
978 ToObjectMapperType<ENUM_TYPE> toObjectMapper = [nameMap] ([[maybe_unused]] const ObjectVariantMapper& mapper, const VariantValue& d,
979 ENUM_TYPE* intoObjOfTypeT) -> void {
980 RequireNotNull (intoObjOfTypeT);
981 auto optVal = nameMap.InverseLookup (d.As<String> ());
982 if (not optVal.has_value ()) [[unlikely]] {
983 DbgTrace ("Enumeration ('{}') value '{}' out of range"_f, type_index{typeid (ENUM_TYPE)}, d);
984 static const auto kException_ = BadFormatException{"Enumeration value out of range"sv};
985 Execution::Throw (kException_);
986 }
987 *intoObjOfTypeT = *optVal;
988 };
989 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (ENUM_TYPE)};
990 }
991 template <typename ENUM_TYPE>
992 inline ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_NamedEnumerations (const Common::EnumNames<ENUM_TYPE>& nameMap)
993 {
994 return MakeCommonSerializer_NamedEnumerations (Containers::Bijection<ENUM_TYPE, String>{nameMap});
995 }
996 template <typename ENUM_TYPE>
997 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_EnumAsInt ()
998 {
999 /*
1000 * Note: we cannot get the enumeration print names - in general. That would be nicer to read, but we don't have
1001 * the data, and this is simple and efficient.
1002 *
1003 * See MakeCommonSerializer_NamedEnumerations
1004 */
1005 static_assert (is_enum_v<ENUM_TYPE>, "This only works for enum types");
1006 using SerializeAsType = typename underlying_type<ENUM_TYPE>::type;
1007 static_assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE), "underlyingtype?");
1008 FromObjectMapperType<ENUM_TYPE> fromObjectMapper = [] ([[maybe_unused]] const ObjectVariantMapper& mapper,
1009 const ENUM_TYPE* fromObjOfTypeT) -> VariantValue {
1010 RequireNotNull (fromObjOfTypeT);
1011 Assert (static_cast<ENUM_TYPE> (static_cast<SerializeAsType> (*fromObjOfTypeT)) == *fromObjOfTypeT); // no round-trip loss
1012 return VariantValue{static_cast<SerializeAsType> (*fromObjOfTypeT)};
1013 };
1014 ToObjectMapperType<ENUM_TYPE> toObjectMapper = [] ([[maybe_unused]] const ObjectVariantMapper& mapper, const VariantValue& d,
1015 ENUM_TYPE* intoObjOfTypeT) -> void {
1016 RequireNotNull (intoObjOfTypeT);
1017 *intoObjOfTypeT = static_cast<ENUM_TYPE> (d.As<SerializeAsType> ());
1018 Assert (static_cast<SerializeAsType> (*intoObjOfTypeT) == d.As<SerializeAsType> ()); // no round-trip loss
1019 if (not(ENUM_TYPE::eSTART <= *intoObjOfTypeT and *intoObjOfTypeT < ENUM_TYPE::eEND)) [[unlikely]] {
1020 using namespace Characters;
1021 DbgTrace ("Enumeration ('{}') value {} out of range"_f, type_index{typeid (ENUM_TYPE)}, static_cast<int> (*intoObjOfTypeT));
1022 static const auto kException_ = BadFormatException{"Enumeration value out of range"_k};
1023 Execution::Throw (kException_);
1024 }
1025 };
1026 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (ENUM_TYPE)};
1027 }
1028 template <typename ACTUAL_CONTAINTER_TYPE, IDefaultConstructForRead KEY_TYPE, IDefaultConstructForRead VALUE_TYPE>
1030 {
1031 FromObjectMapperType<ACTUAL_CONTAINTER_TYPE> fromObjectMapper = [] (const ObjectVariantMapper& mapper,
1032 const ACTUAL_CONTAINTER_TYPE* fromObjOfTypeT) -> VariantValue {
1033 RequireNotNull (fromObjOfTypeT);
1034 FromObjectMapperType<KEY_TYPE> keyMapper{mapper.FromObjectMapper<KEY_TYPE> ()};
1035 FromObjectMapperType<VALUE_TYPE> valueMapper{mapper.FromObjectMapper<VALUE_TYPE> ()};
1036 using namespace Containers::Concrete;
1037 SortedMapping_stdmap<String, VariantValue>::STDMAP<> m; // use std::map instead of Mapping<> as slight speed tweak to avoid virtual call adding
1038 for (const Common::KeyValuePair<KEY_TYPE, VALUE_TYPE>& i : *fromObjOfTypeT) {
1039 m.insert ({mapper.FromObject<KEY_TYPE> (keyMapper, i.fKey).template As<String> (),
1040 mapper.FromObject<VALUE_TYPE> (valueMapper, i.fValue)});
1041 }
1042 return VariantValue{SortedMapping_stdmap<String, VariantValue>{move (m)}};
1043 };
1044 ToObjectMapperType<ACTUAL_CONTAINTER_TYPE> toObjectMapper = [] (const ObjectVariantMapper& mapper, const VariantValue& d,
1045 ACTUAL_CONTAINTER_TYPE* intoObjOfTypeT) -> void {
1046 RequireNotNull (intoObjOfTypeT);
1047 ToObjectMapperType<KEY_TYPE> keyMapper{mapper.ToObjectMapper<KEY_TYPE> ()};
1048 ToObjectMapperType<VALUE_TYPE> valueMapper{mapper.ToObjectMapper<VALUE_TYPE> ()};
1050 intoObjOfTypeT->clear ();
1052 intoObjOfTypeT->Add (mapper.ToObject<KEY_TYPE> (keyMapper, p.fKey), mapper.ToObject<VALUE_TYPE> (valueMapper, p.fValue));
1053 }
1054 };
1055 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (ACTUAL_CONTAINTER_TYPE)};
1056 }
1057 template <typename ACTUAL_CONTAINTER_TYPE, IDefaultConstructForRead KEY_TYPE, IDefaultConstructForRead VALUE_TYPE>
1059 {
1060 return MakeCommonSerializer_WithKeyValuePairAdd_<KEY_TYPE, VALUE_TYPE, ACTUAL_CONTAINTER_TYPE> ();
1061 }
1062 template <typename RANGE_TYPE>
1063 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Range_ (const RangeSerializerOptions& options)
1064 {
1065 using namespace Characters::Literals;
1066 static const String kLowerBoundLabel_{"LowerBound"sv};
1067 static const String kUpperBoundLabel_{"UpperBound"sv};
1068 String lowerBoundLabel = options.fLowerBoundFieldName.value_or (kLowerBoundLabel_);
1069 String upperBoundLabel = options.fUpperBoundFieldName.value_or (kUpperBoundLabel_);
1070 FromObjectMapperType<RANGE_TYPE> fromObjectMapper = [=] (const ObjectVariantMapper& mapper, const RANGE_TYPE* fromObjOfTypeT) -> VariantValue {
1071 RequireNotNull (fromObjOfTypeT);
1072 Mapping<String, VariantValue> m;
1073 if (fromObjOfTypeT->empty ()) {
1074 return VariantValue{};
1075 }
1076 else {
1077 using value_type = typename RANGE_TYPE::value_type;
1078 FromObjectMapperType<value_type> valueMapper{mapper.FromObjectMapper<value_type> ()};
1079 m.Add (lowerBoundLabel, mapper.FromObject<value_type> (valueMapper, fromObjOfTypeT->GetLowerBound ()));
1080 m.Add (upperBoundLabel, mapper.FromObject<value_type> (valueMapper, fromObjOfTypeT->GetUpperBound ()));
1081 return VariantValue{m};
1082 }
1083 };
1084 ToObjectMapperType<RANGE_TYPE> toObjectMapper = [=] (const ObjectVariantMapper& mapper, const VariantValue& d, RANGE_TYPE* intoObjOfTypeT) -> void {
1085 RequireNotNull (intoObjOfTypeT);
1086 Mapping<String, VariantValue> m{d.As<Mapping<String, VariantValue>> ()};
1087 if (m.empty ()) {
1088 *intoObjOfTypeT = RANGE_TYPE{}; // empty maps to empty
1089 }
1090 else {
1091 if (m.size () != 2) [[unlikely]] {
1092 DbgTrace ("Range ('{}') element needs LowerBound and UpperBound"_f, type_index{typeid (RANGE_TYPE)});
1093 static const auto kException_ = BadFormatException{"Range needs LowerBound and UpperBound"sv};
1094 Execution::Throw (kException_);
1095 }
1096 if (not m.ContainsKey (lowerBoundLabel)) [[unlikely]] {
1097 DbgTrace ("Range ('{}') element needs LowerBound"_f, type_index{typeid (RANGE_TYPE)});
1098 static const auto kException_ = BadFormatException{"Range needs 'LowerBound' element"sv};
1099 Execution::Throw (kException_);
1100 }
1101 if (not m.ContainsKey (upperBoundLabel)) [[unlikely]] {
1102 DbgTrace ("Range ('{}') element needs UpperBound"_f, type_index{typeid (RANGE_TYPE)});
1103 static const auto kException_ = BadFormatException{"Range needs 'UpperBound' element"sv};
1104 Execution::Throw (kException_);
1105 }
1106 using value_type = typename RANGE_TYPE::value_type;
1107 ToObjectMapperType<value_type> valueMapper{mapper.ToObjectMapper<value_type> ()};
1108 value_type from{mapper.ToObject<value_type> (valueMapper, *m.Lookup (lowerBoundLabel))};
1109 value_type to{mapper.ToObject<value_type> (valueMapper, *m.Lookup (upperBoundLabel))};
1110 *intoObjOfTypeT = CheckedConverter_Range<RANGE_TYPE> (from, to);
1111 }
1112 };
1113 return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (RANGE_TYPE)};
1114 }
1115 template <typename CLASS>
1116 ObjectVariantMapper::TypeMappingDetails
1117 ObjectVariantMapper::MakeCommonSerializer_ForClassObject_ (const type_index& forTypeInfo, [[maybe_unused]] size_t sizeofObj,
1118 const Traversal::Iterable<StructFieldInfo>& fields,
1119 const ClassMapperOptions<CLASS>& options)
1120 {
1121 using namespace Characters::Literals;
1123 {
1124 // assure each field unique
1125 Containers::MultiSet<StructFieldMetaInfo> t;
1126 for (const auto& i : fields) {
1127 if (i.fFieldMetaInfo_) {
1128 t.Add (*i.fFieldMetaInfo_);
1129 }
1130 }
1131 }
1132 {
1133 // assure each field unique
1134 Containers::MultiSet<StructFieldMetaInfo> t;
1135 for (const auto& i : fields) {
1136 if (i.fFieldMetaInfo_) {
1137 t.Add (*i.fFieldMetaInfo_);
1138 }
1139 }
1140 for (const auto& i : t) {
1141 [[maybe_unused]] bool alreadyInListOfFields = not(i.fCount == 1);
1142 WeakAssert (not alreadyInListOfFields); // not necessarily something we want to prohibit, but overwhelmingly likely a bug/typo
1143 }
1144 }
1145 }
1146 FromObjectMapperType<CLASS> fromObjectMapper = [fields, options] (const ObjectVariantMapper& mapper, const CLASS* fromObjOfTypeT) -> VariantValue {
1147#if Stroika_Foundation_DataExchange_ObjectVariantMapper_USE_NOISY_TRACE_IN_THIS_MODULE_
1148 Debug::TraceContextBumper ctx{"ObjectVariantMapper::TypeMappingDetails::{}::FromObjectMapper"};
1149#endif
1150
1151#if qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities
1152 auto decodingClassActivity =
1153 Execution::LazyEvalActivity{[&] () -> String { return "Encoding {:.50}"_f(type_index{typeid (CLASS)}); }};
1154 Execution::DeclareActivity da{&decodingClassActivity};
1155#endif
1156 Mapping<String, VariantValue> m;
1157 if (options.fBeforeFrom) [[unlikely]] {
1158 m = options.fBeforeFrom (mapper, fromObjOfTypeT).template As<Mapping<String, VariantValue>> (); // so we can extend
1159 }
1160 for (const auto& i : fields) {
1161#if Stroika_Foundation_DataExchange_ObjectVariantMapper_USE_NOISY_TRACE_IN_THIS_MODULE_
1162 DbgTrace ("fieldname = {}, offset={}"_f, i.fSerializedFieldName_, i.fFieldMetaInfo_);
1163#endif
1164 VariantValue vv = [&] () {
1165 const byte* b = i.fFieldMetaInfo_ ? i.fFieldMetaInfo_->GetAddressOfMember (fromObjOfTypeT)
1166 : reinterpret_cast<const byte*> (fromObjOfTypeT);
1167 if (i.fOverrideTypeMapper_) [[unlikely]] {
1168 return i.fOverrideTypeMapper_->GetGenericFromObjectMapper () (mapper, b);
1169 }
1170 else {
1171 Require (i.fFieldMetaInfo_);
1172 return mapper.Lookup_ (i.fFieldMetaInfo_->GetTypeInfo ()).GetGenericFromObjectMapper () (mapper, b);
1173 }
1174 }();
1175 if (not options.fOmitNullEntriesInFromObject or vv.GetType () != VariantValue::eNull) [[likely]] {
1176 m.Add (i.fSerializedFieldName_, vv);
1177 }
1178 }
1179 VariantValue result{m};
1180 if (options.fAfterFrom) [[unlikely]] {
1181 options.fAfterFrom (mapper, fromObjOfTypeT, &result);
1182 }
1183 return result;
1184 };
1185 ToObjectMapperType<CLASS> toObjectMapper = [fields, options] (const ObjectVariantMapper& mapper, const VariantValue& d,
1186 CLASS* intoObjOfTypeT) -> void {
1187#if Stroika_Foundation_DataExchange_ObjectVariantMapper_USE_NOISY_TRACE_IN_THIS_MODULE_
1188 Debug::TraceContextBumper ctx{"ObjectVariantMapper::TypeMappingDetails::{}::ToObjectMapper"};
1189#endif
1190 RequireNotNull (intoObjOfTypeT);
1191#if qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities
1192 auto decodingClassActivity =
1193 Execution::LazyEvalActivity{[&] () -> String { return "Decoding {:.100} into class {}"_f(d, type_index{typeid (CLASS)}); }};
1194 Execution::DeclareActivity da{&decodingClassActivity};
1195#endif
1196 if (options.fBeforeTo) {
1197 options.fBeforeTo (mapper, d, intoObjOfTypeT);
1198 }
1199 Mapping<String, VariantValue> m = d.As<Mapping<String, VariantValue>> ();
1200 for (const auto& i : fields) {
1201#if qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities
1202 auto decodingFieldActivity =
1203 Execution::LazyEvalActivity{[&] () -> String { return "Decoding field {}"_f(i.fSerializedFieldName_); }};
1204 [[maybe_unused]] Execution::DeclareActivity daf{&decodingFieldActivity};
1205#endif
1206 optional<VariantValue> o = m.Lookup (i.fSerializedFieldName_);
1207#if Stroika_Foundation_DataExchange_ObjectVariantMapper_USE_NOISY_TRACE_IN_THIS_MODULE_
1208 DbgTrace ("fieldname = {}, offset={}, present={}"_f, i.fSerializedFieldName_, i.fFieldMetaInfo_, o.has_value ());
1209#endif
1210 if (o) {
1211 byte* b = i.fFieldMetaInfo_ ? i.fFieldMetaInfo_->GetAddressOfMember (intoObjOfTypeT) : reinterpret_cast<byte*> (intoObjOfTypeT);
1212 if (i.fOverrideTypeMapper_) {
1213 i.fOverrideTypeMapper_->GetGenericToObjectMapper () (mapper, *o, b);
1214 }
1215 else {
1216 Require (i.fFieldMetaInfo_);
1217 mapper.Lookup_ (i.fFieldMetaInfo_->GetTypeInfo ()).GetGenericToObjectMapper () (mapper, *o, b);
1218 }
1219 }
1220 }
1221 if (options.fAfterTo) {
1222 options.fAfterTo (mapper, d, intoObjOfTypeT);
1223 }
1224 };
1225 return TypeMappingDetails{fromObjectMapper, toObjectMapper, forTypeInfo};
1226 }
1227 template <typename CLASS>
1228 inline ObjectVariantMapper::TypeMappingDetails
1229 ObjectVariantMapper::MakeCommonSerializer_ForClassObject_and_check_ (const type_index& forTypeInfo, [[maybe_unused]] size_t sizeofObj,
1230 const Traversal::Iterable<StructFieldInfo>& fields,
1231 const ClassMapperOptions<CLASS>& options, const ObjectVariantMapper* use2Validate)
1232 {
1234 // Assure for each field type is registered. This is helpful 99% of the time the assert is triggered.
1235 // If you ever need to avoid it (I don't see how because this mapper doesn't work with circular data structures)
1236 // you can just define a bogus mapper temporarily, and then reset it to the real one before use.
1237 for (const auto& i : fields) {
1238 Require (i.fOverrideTypeMapper_ or i.fFieldMetaInfo_); // don't need to register the type mapper if its specified as a field
1239 if (not i.fOverrideTypeMapper_) {
1240 Assert (i.fFieldMetaInfo_); // cuz need type mapper if fFieldMetaInfo_ not present
1241 if (use2Validate != nullptr) {
1242 (void)use2Validate->Lookup_ (i.fFieldMetaInfo_->GetTypeInfo ());
1243 }
1244 }
1245 }
1246 }
1247 return MakeCommonSerializer_ForClassObject_<CLASS> (forTypeInfo, sizeofObj, fields, options);
1248 }
1249}
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define RequireNotNull(p)
Definition Assertions.h:347
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
Definition Assertions.h:438
#define DbgTrace
Definition Trace.h:309
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual CONTAINER_OF_Key_T As() const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
nonvirtual void Append(ArgByValueType< value_type > item)
Definition Sequence.inl:330
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void AddClass(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< CLASS > &mapperOptions={})
function< VariantValue(const ObjectVariantMapper &mapper, const T *objOfType)> FromObjectMapperType
nonvirtual void AddCommonType(ARGS &&... args)
nonvirtual void AddSubClass(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< CLASS > &mapperOptions={})
Like @AddClass<> - adding a new class based on parameters - but based on the argument baseClass.
nonvirtual ToObjectMapperType< T > ToObjectMapper() const
nonvirtual void operator+=(const TypeMappingDetails &rhs)
static TypeMappingDetails MakeClassSerializer(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< T > &options={})
nonvirtual VariantValue FromObject(const T &from) const
nonvirtual FromObjectMapperType< T > FromObjectMapper() const
nonvirtual optional< T > ToObjectQuietly(const VariantValue &v) const
nonvirtual T ToObject(const VariantValue &v) const
function< void(const ObjectVariantMapper &mapper, const VariantValue &d, T *into)> ToObjectMapperType
nonvirtual void Add(const TypeMappingDetails &s)
nonvirtual void SetTypeMappingRegistry(const TypesRegistry &s)
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
static const Date kMin
Definition Date.h:542
static const TimeOfDay kMin
Definition TimeOfDay.h:174
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
nonvirtual bool empty() const
Returns true iff size() == 0.
Definition Iterable.inl:306
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43
utility for generic code that wishes to add something to a somewhat arbitrary container,...
Definition Adder.h:57
StructFieldInfo(const String &serializedFieldName, const StructFieldMetaInfo &fieldMetaInfo)
static ToObjectMapperType< T > ToObjectMapper(const ToGenericObjectMapperType &toObjectMapper)
static FromObjectMapperType< T > FromObjectMapper(const FromGenericObjectMapperType &fromObjectMapper)