Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
ObjectVariantMapper.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_DataExchange_ObjectVariantMapper_h_
5#define _Stroika_Foundation_DataExchange_ObjectVariantMapper_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10
11#include <filesystem>
12#include <type_traits>
13#include <typeindex>
14#include <variant>
15
19#include "Stroika/Foundation/Common/GUID.h"
21#include "Stroika/Foundation/Containers/Bijection.h"
22#include "Stroika/Foundation/Containers/Collection.h"
23#include "Stroika/Foundation/Containers/KeyedCollection.h"
24#include "Stroika/Foundation/Containers/Mapping.h"
26#include "Stroika/Foundation/Containers/Sequence.h"
27#include "Stroika/Foundation/Containers/Set.h"
30#include "Stroika/Foundation/Containers/SortedMapping.h"
32#include "Stroika/Foundation/Containers/SortedSet.h"
36#include "Stroika/Foundation/Memory/Common.h"
40
41#include "StructFieldMetaInfo.h"
42#include "VariantValue.h"
43
44/**
45 *
46 *
47 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
48 *
49 * TODO:
50 * @todo http://stroika-bugs.sophists.com/browse/STK-558 ObjectVariantMapper::TypesRegistry should use KeyedCollection when that code is ready
51 * use KeyedCollection<> instead of Mapping for fSerializers - was using Set<> which is closer API wise, but Set<> has misfeature
52 * that adding when already there does nothing, and new KeyedCollection will have property - like Mapping - of replacing value.
53 *
54 * @todo Fix MakeCommonSerializer() for tuple<> to be variadic.
55 *
56 * @todo Further cleanups of MakeCommonSerializer<> are needed, but this is probably the right way to go. Use more enable_if
57 * stuff.
58 *
59 * OLD RELATED NOTE WHICH IS PARTLY DONE BUT COMPLETE:
60 * Add support for array to ResetToDefaultTypeRegistry - like we have for struct - using Sequence<>
61 * as the C++ type (maybe others too, vector, more?).
62 *
63 * But unclear how todo ArrayOfWhat?? Maybe the CTOR takes to typeids - not sure how well that works?
64 *
65 * @todo Redo examples (maybe small bits of API) using new Reader/Writer abstract impl
66 * stuff (backends to XML or JSON)
67 *
68 * @todo EFFICIENCY NOTES AND TODO MAYBE IMPROVE?
69 *
70 * This can be moderately efficient, but it is not highly efficient. The use of function
71 * for the serializer/deserializers adds costs.
72 *
73 * When serializing / deserializing - (e.g to/from JSON or XML) - we construct DOM tree which is
74 * intrinsically not very cost effective. We DO have the XML sax parser (but that wont work with this).
75 *
76 * @todo NOTE and TODO
77 * The cast to byte* loses some type safety (we may want to store the class size through template magic)
78 * in the struct type info record, so it can be validated against the offsets in the typeinfo (in debug builds).
79 *
80 * @todo [Long-Term] [Performance] The gist of this design / API is to map C++ objects from/to VariantValue
81 * objects (logically - these are RAM-based representations of an XML or JSON tree - for example).
82 *
83 * We could restructure the API so that it was more SAX-like: instead of taking a VariantValue, it took
84 * something that virtually acted like a VariantValue (gettype, and for array and map types, iterate over the
85 * sub-parts). Similarly - on the FromObject () code - generate a stream of 'write' like calls that
86 * contained atom Variants, and start-array/end-array/start-map/end-map calls.
87 *
88 * This might allow this code to work better with a more efficient json-reader/writer/xml/reader/writer
89 * that also used these sorts of intermediate objects.
90 *
91 * Of course, this ALSO might be implementable without any API changes - just using a special 'rep' for
92 * VariantValue - that was smart about how to it would accessed etc. Needs some thought.
93 *
94 * Anyhow - this is a long-term todo item, so no need to work out details now.
95 *
96 * @todo http://stroika-bugs.sophists.com/browse/STK-743 - Add SupportsAdder concept and use that to simplify use in ObjectVariantMapper
97 */
98
100 class InternetMediaType;
101 class TypedBLOB;
102}
104 class CIDR;
105 class InternetAddress;
106 class URI;
107}
108namespace Stroika::Foundation::Memory {
109 class BLOB;
110}
112
113 using Characters::String;
114 using Containers::KeyedCollection;
115 using Containers::Mapping;
116 using Containers::Sequence;
117 using Containers::Set;
118
119 /**
120 * \brief algorithm used by ObjectOrientedMapper to construct an empty object to read (before fill in fields).
121 *
122 * Normally, this is trivial, and can be ignored. But if you have a type with no default constructor (say because its usually
123 * a bug to default construct) - but maybe sometimes useful (say for ObjectVariantMapper reading) - just specialize this
124 * class.
125 *
126 * This is for use in ObjectVariantMapper::ToObject ()
127 */
128 template <typename T>
130 constexpr T operator() () const
131 {
132#if !qCompilerAndStdLib_defaultconstructibleFails_Buggy
133 static_assert (default_initializable<T>,
134 "to use ObjectVariantMapper::ToObject<> on this type, you must specialize DefaultConstructForRead, or "
135 "externally construct a T object, and pass its address to a T* overload of ToObject");
136#endif
137 return T{};
138 }
139 };
140 template <>
141 struct DefaultConstructForRead<Time::Date>;
142 template <>
143 struct DefaultConstructForRead<Time::DateTime>;
144 template <>
145 struct DefaultConstructForRead<Time::TimeOfDay>;
146 template <>
147 struct DefaultConstructForRead<IO::Network::CIDR>;
148
149 /**
150 * \brief IDefaultConstructForRead checks if argument T is either default_initializable, or has been specialized to allow working with ObjectVariantMapper::ToObject
151 */
152 template <typename T>
153 concept IDefaultConstructForRead = invocable<DefaultConstructForRead<T>>;
154
155#if 0
156 /**
157 * copyable is really needed; default_initializable is needed unless you do some work.
158 * &&DRAFT NOT USED YET
159 */
160 template <typename T>
161 concept IObjectVariantMapper_Serializable = std::copy_constructible<T>;
162
163 /**
164 * &&DRAFT NOT USED YET
165 * &&& NOT RIGHT - JUST PROTYPE..fiddling
166 */
167 template <typename T>
168 concept IObjectVariantMapper_SerializableOrGeneric = IObjectVariantMapper_Serializable<T> or same_as<T, void>;
169
170 /**
171 * &&DRAFT NOT USED YET
172 * &&& NOT RIGHT - JUST PROTYPE..fiddling
173 */
174 template <typename T>
175 concept IObjectVariantMapper_AutomaticallySerializable = IObjectVariantMapper_Serializable<T> and default_initializable<T>;
176#endif
177
178 /**
179 * This isn't very expensive (if your compiler supports cheap thread_local variables) - but its not free, and not very
180 * useful if you have reliable data (just produces better exception messages decoding structured data).
181 */
182#if !defined(qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities)
183#define qStroika_Foundation_DataExchange_ObjectVariantMapper_Activities 1
184#endif
185
186 /**
187 * \brief ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transparently mapped into and out of XML, JSON, etc.
188 *
189 * ObjectVariantMapper IS COPYABLE. Make one instance, register your types into it and use this to
190 * serialized/ToObject
191 *
192 * \par Example Usage
193 * \code
194 * struct SharedContactsConfig_ {
195 * bool fEnabled = false;
196 * optional<DateTime> fLastSynchronizedAt;
197 * Mapping<String,String> fThisPHRsIDToSharedContactID;
198 * };
199 *
200 * ObjectVariantMapper mapper;
201 *
202 * // register each of your mappable (even private) types
203 * mapper.AddClass<SharedContactsConfig_> ({
204 * ObjectVariantMapper::StructFieldInfo{ "Enabled"sv, StructFieldMetaInfo{&SharedContactsConfig_::fEnabled} },
205 * ObjectVariantMapper::StructFieldInfo{ "Last-Synchronized-At"sv, StructFieldMetaInfo{&SharedContactsConfig_::fLastSynchronizedAt} },
206 * ObjectVariantMapper::StructFieldInfo{ "This-HR-ContactID-To-SharedContactID-Map"sv, StructFieldMetaInfo{&SharedContactsConfig_::fThisPHRsIDToSharedContactID} },
207 * }
208 * , {.fOmitNullEntriesInFromObject = true});
209 *
210 * // OR Equivalently (but more commonly/briefly)
211 * mapper.AddClass<SharedContactsConfig_> ({
212 * { "Enabled"sv, &SharedContactsConfig_::fEnabled },
213 * { "Last-Synchronized-At"sv, &SharedContactsConfig_::fLastSynchronizedAt },
214 * { "This-HR-ContactID-To-SharedContactID-Map"sv, &SharedContactsConfig_::fThisPHRsIDToSharedContactID },
215 * });
216 *
217 * SharedContactsConfig_ tmp;
218 * tmp.fEnabled = enabled;
219 * VariantValue v = mapper.FromObject (tmp);
220 *
221 * // at this point - we should have VariantValue object with "Enabled" field.
222 * // This can then be serialized using
223 *
224 * Streams::MemoryStream<byte> tmpStream;
225 * DataExchange::JSON::PrettyPrint (v, tmpStream);
226 *
227 * // THEN deserialized, and mapped back to C++ object form
228 * tmp = mapper.ToObject<SharedContactsConfig_> (DataExchange::JSON::Reader (tmpStream));
229 * if (tmp.fEnabled) {
230 * ...
231 * }
232 * \endcode
233 *
234 * \note Future Design Note:
235 * It would be nice of offer a way to define mappers using c++ user defined attributes
236 * if these existed (@see https://manu343726.github.io/2019-07-14-reflections-on-user-defined-attributes/)
237 *
238 * The current approach is more MODULAR (so not bad), but slightly more verbose, and most other languages
239 * (e.g. c#, java) allow directly annotating objects for serialization (more convenient/terse - appropriate
240 * for some cases like private-ish objects).
241 *
242 * But will have to wait a bit it appears (MSFT still doesn't support reflections TS, and I'm not sure
243 * this can be done with reflections TS).
244 *
245 * \note Design Note (ToObject construction strategy):
246 * \see http://stroika-bugs.sophists.com/browse/STK-1015
247 * Some possibilities:
248 * (1) ToObject () requires pre-constructed object argument, and takes &o as argument, and fills in/overrides fields
249 *
250 * This is extra costly, because it requires 'default constructing' T before assigning/overwriting its field values.
251 * And it requires some mechanism to 'default construct' T.
252 *
253 * But it allows for 'subclassing' T easily. You play the base-class ToObject (&o) functions first, and in sequence.
254 *
255 * (2) ToObject allocates a new smart_ptr<T>.
256 * In this case, we potentially avoid default-constructing and then overwriting/assigning field values. But in case our application
257 * isn't using smart pointers for 'T' - it involves a memory allocation of a smart pointer which will just be thrown away quickly.
258 * It also makes the subclassing story muddy. You need to ALLOCATE the object in the most specific class (subclass) but need to start
259 * filling in fields in the most general (base) class.
260 *
261 * This is a promising idea, but with challenges. Maybe some kind of smart pointer with a custom deleter, so it can be stack allocated by the
262 * caller(?).
263 *
264 * Another variation on this - would be to have for each T/ToObject description - a CONSTRUCTOR function, and a FILL function. Then these
265 * could be somehow combined for the base class/subclass case?
266 */
267 class [[nodiscard]] ObjectVariantMapper {
268 public:
269 /**
270 * FromObjectMapperType<T> defines how to map from a given type to a VariantValue.
271 *
272 * @see FromGenericObjectMapperType
273 * @see ToObjectMapperType
274 */
275 template <typename T>
276 using FromObjectMapperType = function<VariantValue (const ObjectVariantMapper& mapper, const T* objOfType)>;
277
278 public:
279 /**
280 * ToObjectMapperType<T> defines how to map from a VariantValue to the given type;
281 *
282 * @see ToGenericObjectMapperType
283 * @see FromObjectMapperType
284 *
285 * \note - Design Note:
286 * the choice of having an T* into parameter instead of returning T. The returning approach is
287 * in many ways more natural. Doing T *into has the DEFECT, that it requires T to be default constructible (or greatly encourages ;-)).
288 * But using T* into works with subclassing, whereas its less clear how to make the return T approach work with subclassing.
289 *
290 * \see Design Note (ToObject construction strategy)
291 */
292 template <typename T>
293 using ToObjectMapperType = function<void (const ObjectVariantMapper& mapper, const VariantValue& d, T* into)>;
294
295 public:
296 /**
297 * This is a low level mapper - use for a few internal purposes, like pointer to member (class member) mapping, and
298 * for internal storage of mappers.
299 *
300 * \note For performance reasons, we treat this as interchangeable with the real FromObjectMapperType<T>, but
301 * see http://stroika-bugs.sophists.com/browse/STK-601 for details but, with UBSan, we need todo an extra
302 * layer of lambdas mapping, cuz it detects this not totally kosher cast.
303 *
304 * @see ToGenericObjectMapperType
305 * @see FromObjectMapperType<T>
306 */
308
309 public:
310 /**
311 * This is a low level mapper - use for a few internal purposes, like pointer to member (class member) mapping, and
312 * for internal storage of mappers.
313 *
314 * \note For performance reasons, we treat this as interchangeable with the real FromObjectMapperType<T>, but
315 * see http://stroika-bugs.sophists.com/browse/STK-601 for details but, with ubsan, we need todo an extra
316 * layer of lambdas mapping, cuz it detects this not totally kosher cast.
317 *
318 * @see FromGenericObjectMapperType
319 * @see ToObjectMapperType<T>
320 */
322
323 public:
324 /**
325 */
326 template <Common::StdCompat::formattable<wchar_t> T>
327 static const FromObjectMapperType<T> kTraceFromObjectMapper;
328
329 public:
330 /**
331 */
332 template <Common::StdCompat::formattable<wchar_t> T>
333 static const ToObjectMapperType<T> kTraceToObjectMapper;
334
335 public:
336 /**
337 * Defaults to installing basic type mappers (@see ResetToDefaultTypeRegistry).
338 */
340
341 public:
342 /**
343 * Structure to capture all the details of how to map between a VariantValue and an associated C++ structure.
344 * This CAN be directly constructed, and passed into the ObjectVariantMapper (via the Add method), but more commonly
345 * helpers like MakeCommonSerializer () or AddClass will be used.
346 *
347 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a> *
348 * \note fFromObjectMapper_ is nullptr, then this field is added as nullptr.
349 * \note toObjectMapper is nullptr, then it is simply not called (as if did nothing or empty function)
350 */
352 public:
353 /**
354 * \par Example Usage
355 * \code
356 * return TypeMappingDetails{fromObjectMapper, toObjectMapper, typeid (ACTUAL_CONTAINER_TYPE)};
357 * \endcode
358 *
359 * \par Example Usage
360 * \code
361 * auto myReadOnlyPropertyTypeMapper = ObjectVariantMapper::TypeMappingDetails{
362 * ObjectVariantMapper::FromObjectMapperType<MyType2Serialize1_> ([] (const ObjectVariantMapper& mapper, const MyType2Serialize1_* objOfType) -> VariantValue {
363 * return VariantValue{objOfType->fEnabled ? 2 : 99};
364 * }),
365 * ObjectVariantMapper::ToObjectMapperType<MyType2Serialize1_> (nullptr)};
366 * \endcode
367 */
369 TypeMappingDetails (const TypeMappingDetails&) = default;
370 TypeMappingDetails (TypeMappingDetails&&) noexcept = default;
371 explicit TypeMappingDetails (const FromGenericObjectMapperType& fromObjectMapper,
372 const ToGenericObjectMapperType& toObjectMapper, const type_index& forTypeInfo);
373 template <typename T>
374 TypeMappingDetails (const FromObjectMapperType<T>& fromObjectMapper, const ToObjectMapperType<T>& toObjectMapper,
375 const type_index& forTypeInfo = type_index{typeid (T)})
376 requires (not same_as<T, void>);
377
378 public:
379 nonvirtual TypeMappingDetails& operator= (TypeMappingDetails&& rhs) noexcept = default;
380 nonvirtual TypeMappingDetails& operator= (const TypeMappingDetails& rhs) = default;
381
382 public:
383 /**
384 */
385 nonvirtual strong_ordering operator<=> (const TypeMappingDetails& rhs) const;
386
387 public:
388 /**
389 */
390 nonvirtual bool operator== (const TypeMappingDetails& rhs) const;
391
392 public:
393 /**
394 * \see FromGenericObjectMapperType
395 * \see GetGenericFromObjectMapper
396 *
397 * \pre 'T' same_as one TypeMappingDetails constructed from (using type_info dynamic type compare)
398 */
399 template <typename T>
401 template <typename T>
402 nonvirtual FromObjectMapperType<T> FromObjectMapper () const;
403
404 public:
405 /**
406 * \see ToGenericObjectMapperType
407 * \see GetGenericToObjectMapper
408 *
409 * \pre 'T' same_as one TypeMappingDetails constructed from (using type_info dynamic type compare)
410 */
411 template <typename T>
413 template <typename T>
414 nonvirtual ToObjectMapperType<T> ToObjectMapper () const;
415
416 public:
417 /**
418 */
419 nonvirtual type_index GetForType () const;
420
421 public:
422 /**
423 */
424 nonvirtual FromGenericObjectMapperType GetGenericFromObjectMapper () const;
425
426 public:
427 /**
428 */
429 nonvirtual ToGenericObjectMapperType GetGenericToObjectMapper () const;
430
431 public:
432 /**
433 * @see Characters::ToString ();
434 */
435 nonvirtual String ToString () const;
436
437 public:
438 [[deprecated ("Since Stroika v3.0d7 - use overload with typeInfo third")]] explicit TypeMappingDetails (
439 const type_index& forTypeInfo, const FromGenericObjectMapperType& fromObjectMapper, const ToGenericObjectMapperType& toObjectMapper)
440 : TypeMappingDetails{fromObjectMapper, toObjectMapper, forTypeInfo}
441 {
442 }
443 template <typename T>
444 [[deprecated ("Since Stroika v3.0d7 - use overload with typeInfo third")]] TypeMappingDetails (const type_index& forTypeInfo,
445 const FromObjectMapperType<T>& fromObjectMapper,
446 const ToObjectMapperType<T>& toObjectMapper)
447 requires (not same_as<T, void>)
448 : TypeMappingDetails{fromObjectMapper, toObjectMapper, forTypeInfo}
449 {
450 }
451
452 private:
453 template <typename T>
454 static FromGenericObjectMapperType mkGenericFromMapper_ (const FromObjectMapperType<T>& fromObjectMapper);
455 template <typename T>
456 static ToGenericObjectMapperType mkGenericToMapper_ (const ToObjectMapperType<T>& toObjectMapper);
457
458 private:
459 type_index fForType_;
460 FromGenericObjectMapperType fFromObjectMapper_;
461 ToGenericObjectMapperType fToObjectMapper_;
462 };
463
464 public:
465 struct TypesRegistry;
466
467 public:
468 /**
469 * Returns the current set of type mappers.
470 */
471 nonvirtual TypesRegistry GetTypeMappingRegistry () const;
472
473 public:
474 /**
475 * Sets the current set of type mappers.
476 */
477 nonvirtual void SetTypeMappingRegistry (const TypesRegistry& s);
478
479 public:
480 /**
481 * Adds the given type mapper(s). This could have been called 'Merge'.
482 *
483 * \note If a type already exists, the subsequent calls overwrite previous mappings. Only one mapping can exist
484 * at a time for a given type.
485 *
486 * \par Example Usage **Add custom object reader**
487 * \code
488 * using IO::Network::CIDR;
489 * ObjectVariantMapper mapper;
490 * mapper.Add<CIDR> ([](const ObjectVariantMapper& mapper, const CIDR* obj) -> VariantValue { return obj->ToString (); },
491 * [](const ObjectVariantMapper& mapper, const VariantValue& d, CIDR* intoObj) -> void { *intoObj = CIDR{d.As<String> ()}; }
492 * );
493 * \endcode
494 * \code
495 * struct RGBColor {
496 * uint8_t red;
497 * uint8_t green;
498 * uint8_t blue;
499 * };
500 *
501 * ObjectVariantMapper mapper;
502 *
503 * mapper.Add<RGBColor> (
504 * [](const ObjectVariantMapper& mapper, const RGBColor* obj) -> VariantValue {
505 * return "#" + Characters::Format (L"%02x%02x%02x", obj->red, obj->green, obj->blue);
506 * },
507 * [](const ObjectVariantMapper& mapper, const VariantValue& d, RGBColor* intoObj) -> void {
508 * String tmpInBuf = d.As<String> ();
509 * if (tmpInBuf.length () != 7) {
510 * Execution::Throw (DataExchange::BadFormatException{"RGBColor should have length 7")};
511 * }
512 * if (tmpInBuf[0] != '#') {
513 * Execution::Throw (DataExchange::BadFormatException{"RGBColor must start with #")};
514 * }
515 * auto readColorComponent = [](const wchar_t* start, const wchar_t* end) -> uint8_t {
516 * wchar_t buf[1024];
517 * Require (end - start < static_cast<ptrdiff_t> (NEltsOf (buf)));
518 * memcpy (buf, start, (end - start) * sizeof (wchar_t));
519 * buf[(end - start)] = '\0';
520 * wchar_t* e = nullptr;
521 * auto result = wcstoul (buf, &e, 16);
522 * if (e != buf + 2) {
523 * Execution::Throw (DataExchange::BadFormatException{"expected 6 hex bytes")};
524 * }
525 * Assert (result <= 255);
526 * return static_cast<uint8_t> (result);
527 * };
528 * intoObj->red = readColorComponent (tmpInBuf.c_str () + 1, tmpInBuf.c_str () + 3);
529 * intoObj->green = readColorComponent (tmpInBuf.c_str () + 3, tmpInBuf.c_str () + 5);
530 * intoObj->blue = readColorComponent (tmpInBuf.c_str () + 5, tmpInBuf.c_str () + 7);
531 * }
532 * );
533 * \endcode
534 *
535 * \code
536 * inline const DataExchange::ObjectVariantMapper PointerType::kMapper = [] () {
537 * DataExchange::ObjectVariantMapper mapper;
538 * mapper.Add<PointerType> (
539 * [] (const ObjectVariantMapper& mapper, const PointerType* obj) -> VariantValue { return obj->As<String> (); },
540 * [] (const ObjectVariantMapper& mapper, const VariantValue& d, PointerType* intoObj) -> void {
541 * *intoObj = PointerType{d.As<String> ()};
542 * });
543 * return mapper;
544 * }();
545 * \endcode
546 *
547 */
548 nonvirtual void Add (const TypeMappingDetails& s);
549 nonvirtual void Add (const Traversal::Iterable<TypeMappingDetails>& s);
550 nonvirtual void Add (const TypesRegistry& s);
551 nonvirtual void Add (const ObjectVariantMapper& s);
552 template <typename T>
553 nonvirtual void Add (const FromObjectMapperType<T>& fromObjectMapper, const ToObjectMapperType<T>& toObjectMapper);
554
555 public:
556 /**
557 * @aliases Add ()
558 */
559 nonvirtual void operator+= (const TypeMappingDetails& rhs);
560 nonvirtual void operator+= (const Traversal::Iterable<TypeMappingDetails>& rhs);
561 nonvirtual void operator+= (const TypesRegistry& rhs);
562 nonvirtual void operator+= (const ObjectVariantMapper& rhs);
563
564 public:
565 /**
566 * Shortcut for Add (MakeCommonSerializer<T> ()), so \see MakeCommonSerializer<...> for what T/Args are allowed
567 *
568 * So - this is supported for any type for which (@see MakeCommonSerializer) is supported.
569 *
570 * Note this this is not needed (because it's done by default), but is supported,
571 * for the builtin types.
572 *
573 * @see MakeCommonSerializer for details, and restrictions.
574 *
575 * \par Example Usage
576 * \code
577 * ObjectVariantMapper mapper;
578 * mapper.Add (ObjectVariantMapper::MakeCommonSerializer<optional<int>> ()); // long way
579 * mapper.AddCommonType<optional<int>> (); // equivalent, but also checks/asserts underlying
580 * // type has been entered into registry
581 * \endcode
582 *
583 */
584 template <typename T, typename... ARGS>
585 nonvirtual void AddCommonType (ARGS&&... args);
586
587 public:
588 /**
589 * This clears the registry of type mappers, and resets it to the defaults - a set of builtin types,
590 * like String, int, etc.
591 *
592 * Builtin types include:
593 * o bool
594 * o signed char, short int, int, long int, long long int
595 * o unsigned char, unsigned short int, unsigned int, unsigned long int, unsigned long long int
596 * o float, double, long double
597 * o std::filesystem::path
598 * o Date
599 * o DateTime
600 * o Duration
601 * o DurationSeconds
602 * o Common::GUID
603 * o InternetMediaType
604 * o IO::Network::InternetAddress
605 * o IO::Network::URI
606 * o Mapping<String, String>
607 * o Mapping<String, VariantValue>
608 * o String
609 * o TimeOfDay
610 * o VariantValue
611 * o Range<Duration>/Range<Date>/DiscreteRange<Date>/Range<DateTime>
612 * o optional<EACH_OF_THE_ABOVE>
613 *
614 * @todo - IT SOON WILL CONTAIN Sequence<String>, and Sequence<Variant>, as well as vector<> of those types.
615 *
616 * Note - to include any of your user-defined types (structs) - you must use Add () or
617 * AddClass ().
618 *
619 * @see GetTypeMappingRegistry
620 * @see SetTypeMappingRegistry
621 * @see AddClass
622 * @see Add
623 * @see MakeCommonSerializer
624 */
625 nonvirtual void ResetToDefaultTypeRegistry ();
626
627 public:
628 struct StructFieldInfo;
629
630 public:
631 /**
632 */
633 template <typename CLASS>
634 struct ClassMapperOptions {
635 /**
636 * \brief In ObjectVariantMapper::FromObject () -> VariantValue - decides if missing data mapped to null entry in map/object, or just missing
637 */
638 bool fOmitNullEntriesInFromObject{true};
639
640 /**
641 * FromObjectMapperType (to variant value) called before the StructFieldInfo mappers in an AddClass () method. Typically null, but set in subclassing)
642 */
643 FromObjectMapperType<CLASS> fBeforeFrom;
644
645 /**
646 * ToObjectMapperType (to CLASS) called before the StructFieldInfo mappers in an AddClass () method. Typically null, but set in subclassing)
647 */
648 ToObjectMapperType<CLASS> fBeforeTo;
649
650 /**
651 * FromObjectMapperType (to variant value) after before the StructFieldInfo mappers in an AddClass () method. Typically null, but useful as a hook to refine mapping done by default algorithm
652 */
653 function<void (const ObjectVariantMapper& mapper, const CLASS* objOfType, VariantValue* updateVariantValue)> fAfterFrom;
654
655 /**
656 * ToObjectMapperType (to CLASS) after before the StructFieldInfo mappers in an AddClass () method. Typically null, but useful as a hook to refine mapping done by default algorithm
657 */
658 ToObjectMapperType<CLASS> fAfterTo;
659 };
660
661 public:
662 /**
663 * Adds the given class (defined in explicit template argument) with the given list of field.
664 * Also, optionally provide a 'readPreflight' function to be applied to the read-in VariantValue object before
665 * decomposing (into C++ structs), as a helpful backward compatible file format hook.
666 *
667 * \pre AddClass<> requires that each field data type already be pre-loaded into the
668 * Registry, opr be provided as an optional parameter to the StructFieldInfo.
669 *
670 * \par Example Usage
671 * \code
672 * struct MyConfig_ {
673 * IO::Network::URI fURL1_;
674 * IO::Network::URI fURL2_;
675 * };
676 *
677 * ObjectVariantMapper mapper;
678 * mapper.AddCommonType<IO::Network::URI> (); // add default type mapper (using default URL parse)
679 *
680 * // register each of your mappable (even private) types
681 * mapper.AddClass<MyConfig_> ({
682 * { "fURL1_", &SharedContactsConfig_::fURL1_ }, // use default parser
683 * // for fURL2_ - instead - allow parsing of things like 'localhost:1234' - helpful for Common files
684 * { "fURL2_", &SharedContactsConfig_::fURL2_, ObjectVariantMapper::MakeCommonSerializer<IO::Network::URI> () },
685 * });
686 *
687 * MyConfig_ tmp;
688 * tmp.fURL2_ = IO::Network::URI{"http://localhost:1234"};
689 * VariantValue v = mapper.Serialize (tmp);
690 *
691 * Streams::MemoryStream<byte> tmpStream;
692 * DataExchange::JSON::PrettyPrint (v, tmpStream);
693 *
694 * // THEN deserialized, and mapped back to C++ object form
695 * tmp = mapper.ToObject<MyConfig_> (DataExchange::JSON::Reader{tmpStream});
696 * \endcode
697 *
698 * \note furtherDerivedClass operations to type performed AFTER the argument ones here, so that they can change values
699 * (either map to or from object) done in the base 'class' or set of properties being extended.
700 */
701 template <typename CLASS>
702 nonvirtual void AddClass (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions, const ClassMapperOptions<CLASS>& mapperOptions = {});
703
704 public:
705 /**
706 * \brief Like @AddClass<> - adding a new class based on parameters - but based on the argument baseClass.
707 *
708 * \par Example Usage
709 * \code
710 * struct BaseObj_ {
711 * int fVV1{};
712 * };
713 * struct Derived_ : BaseObj_ {
714 * int fVV2{};
715 * };
716 * ObjectVariantMapper mapper;
717 * mapper.AddClass<BaseObj_> ({
718 * {"fVV1", &BaseObj_, fVV1},
719 * });
720 * mapper.AddSubClass<Derived_, BaseObj_> ({
721 * {"fVV2", &Derived_::fVV2},
722 * });
723 * \endcode
724 *
725 * \note AddSubClass captures the existing mapping for BASE_CLASS at the time of this call, so this
726 * can be used to subclass in place, adding a few extra properties.
727 * \code
728 * #if qStroika_Foundation_Debug_AssertionsChecked
729 * mapper.AddSubClass<Network, Network> ({
730 * {"debugProps"sv, &Network::fDebugProps},
731 * });
732 * #endif
733 * \endcode
734 *
735 * // Another example - add 'virtual field' - readonly
736 * \code
737 * mapper.AddSubClass<Network, Network> (
738 * {},
739 * {.fAfterFrom =
740 * [] (const ObjectVariantMapper&, const Network* objOfType, VariantValue* updateResult) -> void {
741 * Mapping<String, VariantValue> m = updateResult->As<Mapping<String, VariantValue>> ();
742 * m.Add ("RandomValue"sv, VariantValue{objOfType->fEnabled ? 2 : 99});
743 * *updateResult = VariantValue{m};
744 * }
745 * });
746 * \endcode
747 */
748 template <typename CLASS, typename BASE_CLASS>
749 nonvirtual void AddSubClass (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions,
750 const ClassMapperOptions<CLASS>& mapperOptions = {});
751
752 public:
753 /**
754 * Returns the function that does the data mapping. This can be used as an optimization to
755 * avoid multiple lookups of the mapper for a given type (say when reading or writing an array).
756 */
757 template <typename T>
759
760 public:
761 /**
762 * Convert a VariantValue object into any C++ object - using the type converters already registered in
763 * this mapper.
764 *
765 * The overloads that takes 'toObjectMapper' are just an optimization, and need not be used, but if used, the value
766 * passed in MUST the the same as that returned by ToObjectMapper ().
767 *
768 * \note The most simple overloads of ToObject () require the type argument T to satisfy IDefaultConstructForRead.
769 * This is normally just amounts to being default initializable, and is not a problem. But if it is, either
770 * use one of the other overloads of ToObject (), or specialize DefaultConstructForRead<T>;
771 */
772 template <IDefaultConstructForRead T>
773 nonvirtual T ToObject (const VariantValue& v) const;
774 template <typename T>
775 nonvirtual void ToObject (const VariantValue& v, T* into) const;
776 template <typename T>
777 nonvirtual void ToObject (const ToObjectMapperType<T>& toObjectMapper, const VariantValue& v, T* into) const;
778 template <IDefaultConstructForRead T>
779 nonvirtual T ToObject (const ToObjectMapperType<T>& toObjectMapper, const VariantValue& v) const;
780
781 public:
782 /**
783 * Same as ToObject, but (just about) any exceptions mapped to just returning nullopt
784 *
785 * \note - if copying T produces an exception, that will still be propagated.
786 *
787 * The purpose of this method is to make it easier when the input source data may or may not contain the fields needed
788 * to deserialize, and the caller wishes to map if they can, but simplify error handling (just ignore inability to read data)
789 * in the case where it cannot be mapped).
790 */
791 template <typename T>
792 nonvirtual optional<T> ToObjectQuietly (const VariantValue& v) const;
793
794 public:
795 /**
796 * Returns the function that does the data mapping. This can be used as an optimization to
797 * avoid multiple lookups of the mapper for a given type (say when reading or writing an array).
798 */
799 template <typename T>
801
802 public:
803 /**
804 * Convert a C++ object to a VariantValue object - using the type converters already registered in
805 * this mapper.
806 *
807 * The overload that takes 'fromObjectMapper' is just an optimization, and need not be used, but if used, the value
808 * passed in MUST the the same as that returned by FromObjectMapper ().
809 */
810 template <typename T>
811 nonvirtual VariantValue FromObject (const T& from) const;
812 template <typename T>
813 nonvirtual VariantValue FromObject (const FromObjectMapperType<T>& fromObjectMapper, const T& from) const;
814
815 public:
816 /**
817 * This creates serializers for many common types.
818 * o Bijection<DOMAIN_TYPE, RANGE_TYPE, TRAITS>
819 * o Collection<T>
820 * o Traversal::DiscreteRange<T, TRAITS>
821 * o KeyedCollection<T, KEY_TYPE, TRAITS>
822 * o Mapping<Key,Value>
823 * o MultiSet<T>
824 * o optional<T>
825 * o Optional<T>
826 * o Range<T,TRAITS>
827 * o Sequence<T>
828 * o Set<T>
829 * o SortedCollection<T>
830 * o SortedKeyedCollection<T, KEY_TYPE, TRAITS>
831 * o SortedMapping<KEY_TYPE, VALUE_TYPE, TRAITS>
832 * o SortedMultiSet<T>
833 * o SortedSet<T>
834 * o Synchronized<T>
835 * o vector<T>
836 * o tuple<...ARGS>
837 * o vector<T>
838 * o enum types (with eSTART/eEND @see Stroika_Define_Enum_Bounds for bounds checking)
839 * o T[N]
840 *
841 * As well as
842 * o all POD types (integer, floating point, bool)
843 * o Time::Date
844 * o Time::DateTime
845 * o Characters::String
846 * o VariantValue
847 * o IO::Network::CIDR
848 * o IO::Network::InternetAddress
849 * o IO::Network::URI
850 * o Time::TimeOfDay
851 * o Common::GUID
852 *
853 *
854 * \note we USED to support type 'void' with the comment:
855 * o void (yes - this is useful for templating)
856 * until Stroika v2.1d13
857 * But the trouble with this is that it matched any unknown type, and was just a no-op. Not crazy bad, but
858 * could be CONFUSING for debugging - when you add a serializer for a type and it doesn't get serialized and you
859 * have no idea why. MAYBE it would be OK if the serializer logged "TYPE IGNORED" or something. Anyhow
860 * got rid of this feature until I can re-observe why its needed, and then maybe re-instate it more carefully.
861 *
862 * This assumes the template parameters for the above objects are also already defined (mostly 'T' above).
863 *
864 * This function also works (but is generally unneeded for) any of the types defined in
865 * @see ResetToDefaultTypeRegistry () (int, short, String, etc).
866 *
867 * Note - all these de-serializers will throw BadDataFormat exceptions if the data somehow doesn't
868 * fit what the de-serializer expects.
869 *
870 * \note For type Mapping<KEY,VALUE>, this could use either the mapping function
871 * MakeCommonSerializer_MappingWithStringishKey or MakeCommonSerializer_MappingAsArrayOfKeyValuePairs.
872 * MakeCommonSerializer_MappingAsArrayOfKeyValuePairs is more general, but MakeCommonSerializer_MappingWithStringishKey
873 * is more commonly the desired output mapping, and so is the default.
874 *
875 * \note It is legal to call MakeCommonSerializer<> on a type where it only knows how to construct the base class type (struct derived : base {})
876 * in which case it produces a serializer that will still work with the given type T, but will only capture the data from base.
877 *
878 * Note - the reason this works is because the object of type "T" is default-constructed outside the de-serializer, and then passed
879 * by address to the de-serializer.
880 */
881 template <typename T, typename... ARGS>
882 static TypeMappingDetails MakeCommonSerializer (ARGS&&... args);
883
884 public:
885 /**
886 * Create a serializer for a CLASS 'T'
887 * @todo migrate this to be part of MakeCommonSerializer probably, but for now like AddClass, but less checking and doesn't add - just creates/returns
888 *
889 * Create a class serializer/de-serializer for the given field descriptions. Start with those from 'baseClass' - as if that was done first.
890 * and then if furtherDerivedClass provided, apply that type mapper as well last (so it gets final say on what's produced).
891 *
892 * \par Example Usage
893 * \code
894 * return MakeClassSerializer<TypedBLOB> ({
895 * {"data"sv, {&TypedBLOB::fData}},
896 * {"type"sv, {&TypedBLOB::fType}},
897 * });
898 * \endcode
899 */
900 template <typename T>
901 static TypeMappingDetails MakeClassSerializer (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions,
902 const ClassMapperOptions<T>& options = {})
903 requires (is_class_v<T>);
904
905 public:
906 template <typename T>
907 [[deprecated]] static TypeMappingDetails MakeClassSerializer (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions,
908 const optional<TypeMappingDetails>& baseClass,
909 const optional<TypeMappingDetails>& furtherDerivedClass = nullopt)
910 requires (is_class_v<T>)
911 {
912 function<void (const ObjectVariantMapper& mapper, const T* objOfType, VariantValue* updateVariantValue)> afterFrom = nullptr;
913 if (furtherDerivedClass and furtherDerivedClass->GetGenericFromObjectMapper ()) {
914 afterFrom = [=] (const ObjectVariantMapper& mapper, const T* objOfType, VariantValue* updateVariantValue) {
915 VariantValue vv = furtherDerivedClass->FromObjectMapper<T> () (mapper, objOfType);
916 *updateVariantValue = vv;
917 };
918 }
919 return MakeClassSerializer<T> (
920 fieldDescriptions,
921 ClassMapperOptions<T>{
922 .fBeforeFrom = baseClass and baseClass->GetGenericFromObjectMapper () ? baseClass->FromObjectMapper<T> () : nullptr,
923 .fBeforeTo = baseClass and baseClass->GetGenericToObjectMapper () ? baseClass->ToObjectMapper<T> () : nullptr,
924 .fAfterFrom = afterFrom,
925 .fAfterTo = furtherDerivedClass and furtherDerivedClass->GetGenericToObjectMapper () ? furtherDerivedClass->ToObjectMapper<T> () : nullptr},
926 nullptr);
927 }
928
929 private:
930 template <typename T>
931 static TypeMappingDetails MakeClassSerializer_ (const Traversal::Iterable<StructFieldInfo>& fieldDescriptions,
932 const ClassMapperOptions<T>& options, const ObjectVariantMapper* mapperToCheckAgainst)
933 requires (is_class_v<T>);
934
935 public:
936 /**
937 * Optional parameter to MakeCommonSerializer, and AddCommonType
938 */
940 optional<String> fLowerBoundFieldName;
941 optional<String> fUpperBoundFieldName;
942 };
943
944 public:
945 /**
946 * Optional parameter to MakeCommonSerializer, and AddCommonType for object of type optional<T>, where you want to
947 * replace the underlying "T" serialization/deserialization as well.
948 */
950 optional<TypeMappingDetails> fTMapper;
951 };
952
953 public:
954 /**
955 */
956 template <typename ENUM_TYPE>
957 static TypeMappingDetails MakeCommonSerializer_NamedEnumerations (const Containers::Bijection<ENUM_TYPE, String>& nameMap);
958 template <typename ENUM_TYPE>
959 static TypeMappingDetails MakeCommonSerializer_NamedEnumerations (const Common::EnumNames<ENUM_TYPE>& nameMap = Common::DefaultNames<ENUM_TYPE>::k);
960
961 public:
962 /**
963 */
964 template <typename ENUM_TYPE>
965 static TypeMappingDetails MakeCommonSerializer_EnumAsInt ();
966
967 public:
968 /**
969 * This works on Any Mapping<KEY,VALUE>, where the Key can be Mapped to / from a String, using
970 * an already defined type-mapper (from KEY_TYPE to/from String) or be of type String.
971 *
972 * It produces a (JSON) output of { 'field1': value1, 'field2' : value2 ... } representation of the mapping.
973 *
974 * @see MakeCommonSerializer_MappingAsArrayOfKeyValuePairs
975 */
976 template <typename ACTUAL_CONTAINTER_TYPE, IDefaultConstructForRead KEY_TYPE = typename ACTUAL_CONTAINTER_TYPE::key_type,
977 IDefaultConstructForRead VALUE_TYPE = typename ACTUAL_CONTAINTER_TYPE::mapped_type>
978 static TypeMappingDetails MakeCommonSerializer_MappingWithStringishKey ();
979
980 public:
981 /**
982 * This works on Any Mapping<KEY,VALUE>.
983 *
984 * It produces a (JSON) output of [ [ field1, value1 ], [ field2, value2 ], ... } representation of the mapping.
985 *
986 * @see MakeCommonSerializer_MappingWithStringishKey
987 */
988 template <typename ACTUAL_CONTAINTER_TYPE, IDefaultConstructForRead KEY_TYPE = typename ACTUAL_CONTAINTER_TYPE::key_type,
989 IDefaultConstructForRead VALUE_TYPE = typename ACTUAL_CONTAINTER_TYPE::mapped_type>
990 static TypeMappingDetails MakeCommonSerializer_MappingAsArrayOfKeyValuePairs ();
991
992 public:
993 /**
994 * Can be used with any container class which you append with Containers::Adapters::Adder
995 */
996 template <Containers::Adapters::IAddableTo ACTUAL_CONTAINER_TYPE>
997 static TypeMappingDetails MakeCommonSerializer_WithAdder ();
998
999 public:
1000 /**
1001 * @see Characters::ToString ();
1002 */
1003 nonvirtual String ToString () const;
1004
1005 private:
1006 template <typename T>
1007 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (T*);
1008 template <typename DOMAIN_TYPE, typename RANGE_TYPE>
1009 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Containers::Bijection<DOMAIN_TYPE, RANGE_TYPE>*);
1010 template <typename T>
1011 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (Containers::Collection<T>*);
1012 template <typename T, typename TRAITS>
1013 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Traversal::DiscreteRange<T, TRAITS>*);
1014 template <typename T, typename KEY_TYPE, typename TRAITS>
1015 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (Containers::KeyedCollection<T, KEY_TYPE, TRAITS>*);
1016 template <typename KEY_TYPE, typename VALUE_TYPE>
1017 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Mapping<KEY_TYPE, VALUE_TYPE>*);
1018 template <typename T>
1019 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (optional<T>*);
1020 template <typename T, typename TRAITS>
1021 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Traversal::Range<T, TRAITS>*);
1022 template <typename T>
1023 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Sequence<T>*);
1024 template <typename T>
1025 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Set<T>*);
1026 template <typename T, typename TRAITS>
1027 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Execution::Synchronized<T, TRAITS>*);
1028 template <typename T>
1029 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const vector<T>*);
1030 template <typename T1, typename T2>
1031 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const pair<T1, T2>*);
1032 template <typename T>
1033 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Common::CountedValue<T>*);
1034 template <typename T1, typename T2>
1035 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const Common::KeyValuePair<T1, T2>*);
1036 template <typename T1>
1037 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const tuple<T1>*);
1038 template <typename T1, typename T2>
1039 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const tuple<T1, T2>*);
1040 template <typename T1, typename T2, typename T3>
1041 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const tuple<T1, T2, T3>*);
1042 template <typename T, size_t SZ>
1043 nonvirtual void AssertDependentTypesAlreadyInRegistry_ (const T (*)[SZ]);
1044
1045 private:
1046 template <typename T>
1047 static TypeMappingDetails MakeCommonSerializer_ (const Math::CommonStatistics<T>*);
1048 template <typename DOMAIN_TYPE, typename RANGE_TYPE>
1049 static TypeMappingDetails MakeCommonSerializer_ (const Containers::Bijection<DOMAIN_TYPE, RANGE_TYPE>*);
1050 template <typename T>
1051 static TypeMappingDetails MakeCommonSerializer_ (const Containers::Collection<T>*);
1052 template <typename T, typename TRAITS>
1053 static TypeMappingDetails MakeCommonSerializer_ (const Traversal::DiscreteRange<T, TRAITS>*);
1054 template <typename KEY_TYPE, typename VALUE_TYPE>
1055 static TypeMappingDetails MakeCommonSerializer_ (const Mapping<KEY_TYPE, VALUE_TYPE>*);
1056 template <typename T>
1057 static TypeMappingDetails MakeCommonSerializer_ (const Containers::MultiSet<T>*);
1058 template <typename T>
1059 static TypeMappingDetails MakeCommonSerializer_ (const optional<T>*);
1060 template <typename T>
1061 static TypeMappingDetails MakeCommonSerializer_ (const optional<T>*, const OptionalSerializerOptions& options);
1062 template <typename T, typename KEY_TYPE, typename TRAITS>
1063 static TypeMappingDetails MakeCommonSerializer_ (const Containers::KeyedCollection<T, KEY_TYPE, TRAITS>*);
1064 template <typename T, typename TRAITS, typename... ARGS>
1065 static TypeMappingDetails MakeCommonSerializer_ (const Traversal::Range<T, TRAITS>*, ARGS&&... args);
1066 template <typename T>
1067 static TypeMappingDetails MakeCommonSerializer_ (const Sequence<T>*);
1068 template <typename T>
1069 static TypeMappingDetails MakeCommonSerializer_ (const Set<T>*);
1070 template <typename T>
1071 static TypeMappingDetails MakeCommonSerializer_ (const Containers::SortedCollection<T>*);
1072 template <typename T, typename KEY_TYPE, typename TRAITS>
1074 template <typename KEY_TYPE, typename VALUE_TYPE>
1075 static TypeMappingDetails MakeCommonSerializer_ (const Containers::SortedMapping<KEY_TYPE, VALUE_TYPE>*);
1076 template <typename T>
1077 static TypeMappingDetails MakeCommonSerializer_ (const Containers::SortedMultiSet<T>*);
1078 template <typename T>
1079 static TypeMappingDetails MakeCommonSerializer_ (const Containers::SortedSet<T>*);
1080 template <typename T, typename TRAITS>
1081 static TypeMappingDetails MakeCommonSerializer_ (const Execution::Synchronized<T, TRAITS>*);
1082 static TypeMappingDetails MakeCommonSerializer_ (const Memory::BLOB*);
1083 static TypeMappingDetails MakeCommonSerializer_ (const InternetMediaType*);
1084 static TypeMappingDetails MakeCommonSerializer_ (const TypedBLOB*);
1085 static TypeMappingDetails MakeCommonSerializer_ (const IO::Network::CIDR*);
1086 static TypeMappingDetails MakeCommonSerializer_ (const IO::Network::InternetAddress*);
1087 static TypeMappingDetails MakeCommonSerializer_ (const IO::Network::URI*);
1088 static TypeMappingDetails MakeCommonSerializer_ (const Common::GUID*, VariantValue::Type representAs = VariantValue::Type::eString);
1089
1090 static TypeMappingDetails MakeCommonSerializer_ (const Time::Duration*, Characters ::FloatConversion::Precision p);
1091
1092 template <typename T>
1093 static TypeMappingDetails MakeCommonSerializer_ (const vector<T>*);
1094 template <typename T1, typename T2>
1095 static TypeMappingDetails MakeCommonSerializer_ (const pair<T1, T2>*);
1096 template <typename T>
1097 static TypeMappingDetails MakeCommonSerializer_ (const Common::CountedValue<T>*);
1098 template <typename T1, typename T2>
1099 static TypeMappingDetails MakeCommonSerializer_ (const Common::KeyValuePair<T1, T2>*);
1100 template <typename T1>
1101 static TypeMappingDetails MakeCommonSerializer_ (const tuple<T1>*);
1102 template <typename T1, typename T2>
1103 static TypeMappingDetails MakeCommonSerializer_ (const tuple<T1, T2>*);
1104 template <typename T1, typename T2, typename T3>
1105 static TypeMappingDetails MakeCommonSerializer_ (const tuple<T1, T2, T3>*);
1106 template <typename T>
1107 static TypeMappingDetails MakeCommonSerializer_ (const T*)
1108 requires (is_enum_v<T>);
1109 template <typename T, size_t SZ>
1110 static TypeMappingDetails MakeCommonSerializer_ (const T (*)[SZ]);
1111
1112 private:
1113 template <typename KEY_TYPE, typename VALUE_TYPE, typename ACTUAL_CONTAINER_TYPE>
1114 static TypeMappingDetails MakeCommonSerializer_WithKeyValuePairAdd_ ();
1115
1116 private:
1117 template <typename RANGE_TYPE>
1118 static TypeMappingDetails MakeCommonSerializer_Range_ (const RangeSerializerOptions& options = {});
1119
1120 private:
1121 template <typename CLASS>
1122 static TypeMappingDetails MakeCommonSerializer_ForClassObject_ (const type_index& forTypeInfo, size_t sizeofObj,
1124 const ClassMapperOptions<CLASS>& options);
1125 template <typename CLASS>
1126 static TypeMappingDetails MakeCommonSerializer_ForClassObject_and_check_ (const type_index& forTypeInfo, size_t sizeofObj,
1128 const ClassMapperOptions<CLASS>& options,
1129 const ObjectVariantMapper* use2Validate = nullptr);
1130
1131 private:
1132 nonvirtual TypeMappingDetails Lookup_ (const type_index& forTypeInfo) const;
1133
1134 public:
1135 /**
1136 */
1137 struct TypesRegistry {
1138 public:
1139 TypesRegistry (const Traversal::Iterable<TypeMappingDetails>& src);
1140
1141 public:
1142 nonvirtual optional<TypeMappingDetails> Lookup (type_index t) const;
1143
1144 public:
1145 /**
1146 * \note Add () may update/replace an existing mapping, without prejudice.
1147 */
1148 nonvirtual void Add (const TypeMappingDetails& typeMapDetails);
1149 nonvirtual void Add (const Traversal::Iterable<TypeMappingDetails>& typeMapDetails);
1150
1151 public:
1152 nonvirtual Traversal::Iterable<TypeMappingDetails> GetMappers () const;
1153
1154 public:
1155 /**
1156 * @aliases Add ()
1157 */
1158 nonvirtual void operator+= (const TypeMappingDetails& typeMapDetails);
1159 nonvirtual void operator+= (const Traversal::Iterable<TypeMappingDetails>& typeMapDetails);
1160
1161 public:
1162 /**
1163 * @see Characters::ToString ();
1164 */
1165 nonvirtual String ToString () const;
1166
1167 private:
1168 struct TypeMappingDetails_Extractor_ {
1169 auto operator() (const TypeMappingDetails& t) const -> type_index
1170 {
1171 return t.GetForType ();
1172 };
1173 };
1175 KeyedCollection<TypeMappingDetails, type_index, TypeMappingDetails_Traits_> fSerializers_;
1176 };
1177
1178 private:
1179 TypesRegistry fTypeMappingRegistry_;
1180 };
1181
1182 /**
1183 * This is just for use the with the ObjectVariantMapper::AddClass<> (and related) methods, to describe a
1184 * user-defined type (CLASS).
1185 */
1187 public:
1188 /**
1189 *
1190 * ***DEPRECATED SINCE STROIKA v3.0d8...
1191 *
1192 * \brief In ObjectVariantMapper::FromObject () -> VariantValue - decides if missing data mapped to null entry in map/object, or just missing
1193 */
1195 eOmit,
1196 eInclude,
1197
1198 Stroika_Define_Enum_Bounds (eOmit, eInclude)
1199 };
1200 /**
1201 * ***DEPRECATED SINCE STROIKA v3.0d8...
1202 * \brief In ObjectVariantMapper::FromObject () -> VariantValue - parent object created with missing values if missing from object
1203 */
1204 [[deprecated ("Since Stroika v3.0d8")]] static constexpr NullFieldHandling eOmitNullFields = NullFieldHandling::eOmit; // instead of using NullFieldHandling::eOmit
1205
1206 /**
1207 * ***DEPRECATED SINCE STROIKA v3.0d8...
1208 * \brief In ObjectVariantMapper::FromObject () -> VariantValue - parent object created with explicitly null values if missing from object
1209 */
1210 [[deprecated ("Since Stroika v3.0d8")]] static constexpr NullFieldHandling eIncludeNullFields =
1211 NullFieldHandling::eInclude; // instead of using NullFieldHandling::eInclude
1212
1213 private:
1214 /*
1215 * Required for a an actual field mapper, but if empty, implies a reader/writer for the entire object.
1216 *
1217 * \note Since v3.0d7 - this is required to be non-empty (or empty use deprecated rather)
1218 */
1219 String fSerializedFieldName_;
1220
1221 /*
1222 * if missing - then pass in parent object, then fOverrideTypeMapper_ required ****THIS USE DEPRECATED*****
1223 * \note Since v3.0d7 - this is required to be null-null (or null use deprecated rather)
1224 */
1225 optional<StructFieldMetaInfo> fFieldMetaInfo_;
1226
1227 /*
1228 * if fFieldMetaInfo_ == nullopt, fOverrideTypeMapper_ is required, and is the mapper used for the entire
1229 * object. (NOTE SINCE 3.0d7 - fFieldMetaInfo_==nullopt deprecated); but this is still optional.
1230 */
1231 optional<TypeMappingDetails> fOverrideTypeMapper_;
1232
1233 public:
1234 /**
1235 * \par Example Usage
1236 * \code
1237 * {"Int-1"sv, &SharedContactsConfig_::fInt1},
1238 * \endcode
1239 *
1240 * \par Example Usage
1241 * \code
1242 * ObjectVariantMapper::StructFieldInfo{"Int-1"sv, StructFieldMetaInfo{&SharedContactsConfig_::fInt1}},
1243 * \endcode
1244 *
1245 * \par Example Usage
1246 * \code
1247 * {"BasicArray1"sv, &SharedContactsConfig_::fBasicArray1, ObjectVariantMapper::MakeCommonSerializer<int[5]> ()},
1248 * \endcode
1249 */
1250 StructFieldInfo (const String& serializedFieldName, const StructFieldMetaInfo& fieldMetaInfo);
1251 StructFieldInfo (const String& serializedFieldName, const StructFieldMetaInfo& fieldMetaInfo, const optional<TypeMappingDetails>& overrideTypeMapper);
1252
1253 public:
1254 [[deprecated ("Since Stroika v3.0d8 - NullFieldHandling::eOmit is new default, use AddClass options arg "
1255 "ClassMapperOptions<T>{.fOmitNullEntriesInFromObject = false} for eInclude behevior")]] StructFieldInfo (const String& serializedFieldName,
1256 const StructFieldMetaInfo& fieldMetaInfo,
1257 [[maybe_unused]] NullFieldHandling fromObjectNullHandling)
1258 : StructFieldInfo{serializedFieldName, fieldMetaInfo}
1259 {
1260 WeakAssert (fromObjectNullHandling == NullFieldHandling::eInclude); // the default changed for this case
1261 }
1262 [[deprecated ("Since Stroika v3.0d8 - NullFieldHandling::eOmit is new default, use AddClass options arg "
1263 "ClassMapperOptions<T>{.fOmitNullEntriesInFromObject = false} for eInclude behevior")]] StructFieldInfo (const String& serializedFieldName,
1264 const StructFieldMetaInfo& fieldMetaInfo,
1265 const optional<TypeMappingDetails>& overrideTypeMapper,
1266 [[maybe_unused]] NullFieldHandling fromObjectNullHandling)
1267 : StructFieldInfo{serializedFieldName, fieldMetaInfo, overrideTypeMapper}
1268 {
1269 WeakAssert (fromObjectNullHandling == NullFieldHandling::eInclude); // the default changed for this case
1270 }
1271 [[deprecated ("Since Stroika v3.0d7 - dont use StructFieldInfo with missing filedMetaInfo - instead use type override of owning "
1272 "object)")]] StructFieldInfo (const String& serializedFieldName, TypeMappingDetails overrideTypeMapper,
1273 [[maybe_unused]] NullFieldHandling fromObjectNullHandling = NullFieldHandling::eInclude)
1274 : fSerializedFieldName_{serializedFieldName}
1275 , fOverrideTypeMapper_{overrideTypeMapper}
1276 {
1277 }
1278
1279 public:
1280 /**
1281 */
1282 nonvirtual String GetSerializedFieldName () const;
1283
1284 public:
1285 /**
1286 */
1287 nonvirtual StructFieldMetaInfo GetStructFieldMetaInfo () const;
1288
1289 public:
1290 /**
1291 */
1292 nonvirtual optional<TypeMappingDetails> GetOverrideTypeMapper () const;
1293
1294 public:
1295 friend class ObjectVariantMapper;
1296 };
1297
1298 template <>
1299 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<bool> ();
1300 template <>
1301 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<signed char> ();
1302 template <>
1303 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<short int> ();
1304 template <>
1305 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<int> ();
1306 template <>
1307 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<long int> ();
1308 template <>
1309 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<long long int> ();
1310 template <>
1311 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<unsigned char> ();
1312 template <>
1313 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<unsigned short int> ();
1314 template <>
1315 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<unsigned int> ();
1316 template <>
1317 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<unsigned long int> ();
1318 template <>
1319 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<unsigned long long int> ();
1320 template <>
1321 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<float> ();
1322 template <>
1323 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<double> ();
1324 template <>
1325 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<long double> ();
1326 template <>
1327 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<filesystem::path> ();
1328 template <>
1329 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Time::Date> ();
1330 template <>
1331 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Time::DateTime> ();
1332 template <>
1333 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Characters::String> ();
1334 template <>
1335 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<VariantValue> ();
1336 template <>
1337 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Time::Duration> ();
1338 template <>
1339 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Time::DurationSeconds> ();
1340 template <>
1341 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Time::TimeOfDay> ();
1342 template <>
1343 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Mapping<Characters::String, Characters::String>> ();
1344 template <>
1345 ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Mapping<Characters::String, VariantValue>> ();
1346
1347}
1348
1349/*
1350 ********************************************************************************
1351 ***************************** Implementation Details ***************************
1352 ********************************************************************************
1353 */
1354#include "ObjectVariantMapper.inl"
1355
1356#endif /*_Stroika_Foundation_DataExchange_ObjectVariantMapper_h_*/
#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 Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Bijection allows for the bijective (1-1) association of two elements.
Definition Bijection.h:103
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
Definition Collection.h:102
a cross between Mapping<KEY, T> and Collection<T> and Set<T>
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Definition Sequence.h:187
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Definition Set.h:105
A SortedCollection is a Collection<T> which remains sorted (iteration produces items sorted) even as ...
A SortedKeyedCollection is a KeyedCollection<T> which remains sorted (iteration produces items sorted...
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 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
TypedBLOB is a named tuple<Memory::BLOB, optional<InternetMediaType>> - with friendlier names,...
Definition TypedBLOB.h:48
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
Wrap any object with Synchronized<> and it can be used similarly to the base type,...
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
A DiscreteRange is a Range where the underlying endpoints are integral (discrete, not continuous); th...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
IDefaultConstructForRead checks if argument T is either default_initializable, or has been specialize...
algorithm used by ObjectOrientedMapper to construct an empty object to read (before fill in fields).
NullFieldHandling
In ObjectVariantMapper::FromObject () -> VariantValue - decides if missing data mapped to null entry ...
static ToObjectMapperType< T > ToObjectMapper(const ToGenericObjectMapperType &toObjectMapper)
static FromObjectMapperType< T > FromObjectMapper(const FromGenericObjectMapperType &fromObjectMapper)