1 /***********************************************************************************************************************************
2 Variant Data Type
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <errno.h>
7 #include <inttypes.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <strings.h>
13
14 #include "common/debug.h"
15 #include "common/memContext.h"
16 #include "common/type/convert.h"
17 #include "common/type/variant.h"
18
19 /***********************************************************************************************************************************
20 Constant variants that are generally useful
21 ***********************************************************************************************************************************/
22 // Used to declare Bool Variant constants that will be externed using VARIANT_DECLARE(). Must be used in a .c file.
23 #define VARIANT_BOOL_EXTERN(name, dataParam) \
24 const Variant *const name = ((const Variant *)&(const VariantBoolPub){.type = varTypeBool, .data = dataParam})
25
26 VARIANT_BOOL_EXTERN(BOOL_FALSE_VAR, false);
27 VARIANT_BOOL_EXTERN(BOOL_TRUE_VAR, true);
28
29 /***********************************************************************************************************************************
30 Information about the variant
31 ***********************************************************************************************************************************/
32 struct Variant
33 {
34 VariantPub pub; // Publicly accessible variables
35 };
36
37 typedef struct VariantBool
38 {
39 VariantBoolPub pub; // Publicly accessible variables
40 MemContext *memContext;
41 } VariantBool;
42
43 typedef struct VariantInt
44 {
45 VariantIntPub pub; // Publicly accessible variables
46 MemContext *memContext;
47 } VariantInt;
48
49 typedef struct VariantInt64
50 {
51 VariantInt64Pub pub; // Publicly accessible variables
52 MemContext *memContext;
53 } VariantInt64;
54
55 typedef struct VariantKeyValue
56 {
57 VARIANT_COMMON
58 KeyValue *data; // KeyValue data
59 MemContext *memContext;
60 } VariantKeyValue;
61
62 typedef struct VariantString
63 {
64 VariantStringPub pub; // Publicly accessible variables
65 MemContext *memContext;
66 } VariantString;
67
68 typedef struct VariantUInt
69 {
70 VariantUIntPub pub; // Publicly accessible variables
71 MemContext *memContext;
72 } VariantUInt;
73
74 typedef struct VariantUInt64
75 {
76 VariantUInt64Pub pub; // Publicly accessible variables
77 MemContext *memContext;
78 } VariantUInt64;
79
80 typedef struct VariantVariantList
81 {
82 VARIANT_COMMON
83 VariantList *data; // VariantList data
84 MemContext *memContext;
85 } VariantVariantList;
86
87 /***********************************************************************************************************************************
88 Variant type names
89 ***********************************************************************************************************************************/
90 static const char *const variantTypeName[] =
91 {
92 "bool", // varTypeBool
93 "int", // varTypeInt
94 "int64", // varTypeInt64
95 "KeyValue", // varTypeKeyValue
96 "String", // varTypeString
97 "unsigned int", // varTypeUInt
98 "uint64", // varTypeUInt64
99 "VariantList", // varTypeVariantList
100 };
101
102 /**********************************************************************************************************************************/
103 Variant *
varDup(const Variant * this)104 varDup(const Variant *this)
105 {
106 FUNCTION_TEST_BEGIN();
107 FUNCTION_TEST_PARAM(VARIANT, this);
108 FUNCTION_TEST_END();
109
110 Variant *result = NULL;
111
112 if (this != NULL)
113 {
114 switch (varType(this))
115 {
116 case varTypeBool:
117 result = varNewBool(varBool(this));
118 break;
119
120 case varTypeInt:
121 result = varNewInt(varInt(this));
122 break;
123
124 case varTypeInt64:
125 result = varNewInt64(varInt64(this));
126 break;
127
128 case varTypeKeyValue:
129 {
130 VariantKeyValue *keyValue = memNew(sizeof(VariantKeyValue));
131
132 *keyValue = (VariantKeyValue)
133 {
134 .memContext = memContextCurrent(),
135 .type = varTypeKeyValue,
136 .data = kvDup(varKv(this)),
137 };
138
139 result = (Variant *)keyValue;
140 break;
141 }
142
143 case varTypeString:
144 result = varNewStr(varStr(this));
145 break;
146
147 case varTypeUInt:
148 result = varNewUInt(varUInt(this));
149 break;
150
151 case varTypeUInt64:
152 result = varNewUInt64(varUInt64(this));
153 break;
154
155 case varTypeVariantList:
156 result = varNewVarLst(varVarLst(this));
157 break;
158 }
159 }
160
161 FUNCTION_TEST_RETURN(result);
162 }
163
164 /**********************************************************************************************************************************/
165 bool
varEq(const Variant * this1,const Variant * this2)166 varEq(const Variant *this1, const Variant *this2)
167 {
168 FUNCTION_TEST_BEGIN();
169 FUNCTION_TEST_PARAM(VARIANT, this1);
170 FUNCTION_TEST_PARAM(VARIANT, this2);
171 FUNCTION_TEST_END();
172
173 bool result = false;
174
175 // Test if both variants are non-null
176 if (this1 != NULL && this2 != NULL)
177 {
178 // Test if both variants are of the same type
179 if (varType(this1) == varType(this2))
180 {
181 switch (varType(this1))
182 {
183 case varTypeBool:
184 result = varBool(this1) == varBool(this2);
185 break;
186
187 case varTypeInt:
188 result = varInt(this1) == varInt(this2);
189 break;
190
191 case varTypeInt64:
192 result = varInt64(this1) == varInt64(this2);
193 break;
194
195 case varTypeString:
196 result = strEq(varStr(this1), varStr(this2));
197 break;
198
199 case varTypeUInt:
200 result = varUInt(this1) == varUInt(this2);
201 break;
202
203 case varTypeUInt64:
204 result = varUInt64(this1) == varUInt64(this2);
205 break;
206
207 default:
208 THROW_FMT(AssertError, "unable to test equality for %s", variantTypeName[varType(this1)]);
209 }
210 }
211 }
212 // Else they are equal if they are both null
213 else
214 result = this1 == NULL && this2 == NULL;
215
216 FUNCTION_TEST_RETURN(result);
217 }
218
219 /**********************************************************************************************************************************/
220 Variant *
varNewBool(bool data)221 varNewBool(bool data)
222 {
223 FUNCTION_TEST_BEGIN();
224 FUNCTION_TEST_PARAM(BOOL, data);
225 FUNCTION_TEST_END();
226
227 // Allocate memory for the variant and set the type and data
228 VariantBool *this = memNew(sizeof(VariantBool));
229
230 *this = (VariantBool)
231 {
232 .pub =
233 {
234 .type = varTypeBool,
235 .data = data,
236 },
237 .memContext = memContextCurrent(),
238 };
239
240 FUNCTION_TEST_RETURN((Variant *)this);
241 }
242
243 /**********************************************************************************************************************************/
244 bool
varBool(const Variant * this)245 varBool(const Variant *this)
246 {
247 FUNCTION_TEST_BEGIN();
248 FUNCTION_TEST_PARAM(VARIANT, this);
249 FUNCTION_TEST_END();
250
251 ASSERT(this != NULL);
252 ASSERT(varType(this) == varTypeBool);
253
254 FUNCTION_TEST_RETURN(((VariantBool *)this)->pub.data);
255 }
256
257 bool
varBoolForce(const Variant * this)258 varBoolForce(const Variant *this)
259 {
260 FUNCTION_TEST_BEGIN();
261 FUNCTION_TEST_PARAM(VARIANT, this);
262 FUNCTION_TEST_END();
263
264 ASSERT(this != NULL);
265
266 bool result = false;
267
268 switch (varType(this))
269 {
270 case varTypeBool:
271 result = varBool(this);
272 break;
273
274 case varTypeInt:
275 result = varInt(this) != 0;
276 break;
277
278 case varTypeInt64:
279 result = varInt64(this) != 0;
280 break;
281
282 case varTypeString:
283 {
284 // List of false/true boolean string values. Note that false/true values must be equal.
285 static const char *const boolString[] =
286 {
287 "n", "f", "0", "no", FALSE_Z, "off",
288 "y", "t", "1", "yes", TRUE_Z, "on",
289 };
290
291 // Search for the string
292 const char *string = strZ(varStr(this));
293 unsigned int boolIdx;
294
295 for (boolIdx = 0; boolIdx < sizeof(boolString) / sizeof(char *); boolIdx++)
296 if (strcasecmp(string, boolString[boolIdx]) == 0)
297 break;
298
299 // If string was not found then not a boolean
300 if (boolIdx == sizeof(boolString) / sizeof(char *))
301 THROW_FMT(FormatError, "unable to convert str '%s' to bool", string);
302
303 // False if in first half of list, true if in second half
304 result = boolIdx / (sizeof(boolString) / sizeof(char *) / 2);
305
306 break;
307 }
308
309 case varTypeUInt:
310 result = varUInt(this) != 0;
311 break;
312
313 case varTypeUInt64:
314 result = varUInt64(this) != 0;
315 break;
316
317 default:
318 THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeBool]);
319 }
320
321 FUNCTION_TEST_RETURN(result);
322 }
323
324 /**********************************************************************************************************************************/
325 Variant *
varNewInt(int data)326 varNewInt(int data)
327 {
328 FUNCTION_TEST_BEGIN();
329 FUNCTION_TEST_PARAM(INT, data);
330 FUNCTION_TEST_END();
331
332 // Allocate memory for the variant and set the type and data
333 VariantInt *this = memNew(sizeof(VariantInt));
334
335 *this = (VariantInt)
336 {
337 .pub =
338 {
339 .type = varTypeInt,
340 .data = data,
341 },
342 .memContext = memContextCurrent(),
343 };
344
345 FUNCTION_TEST_RETURN((Variant *)this);
346 }
347
348 /**********************************************************************************************************************************/
349 int
varInt(const Variant * this)350 varInt(const Variant *this)
351 {
352 FUNCTION_TEST_BEGIN();
353 FUNCTION_TEST_PARAM(VARIANT, this);
354 FUNCTION_TEST_END();
355
356 ASSERT(this != NULL);
357 ASSERT(varType(this) == varTypeInt);
358
359 FUNCTION_TEST_RETURN(((VariantInt *)this)->pub.data);
360 }
361
362 int
varIntForce(const Variant * this)363 varIntForce(const Variant *this)
364 {
365 FUNCTION_TEST_BEGIN();
366 FUNCTION_TEST_PARAM(VARIANT, this);
367 FUNCTION_TEST_END();
368
369 ASSERT(this != NULL);
370
371 int result = 0;
372
373 switch (varType(this))
374 {
375 case varTypeBool:
376 result = varBool(this);
377 break;
378
379 case varTypeInt:
380 result = varInt(this);
381 break;
382
383 case varTypeInt64:
384 {
385 int64_t resultTest = varInt64(this);
386
387 // Make sure the value fits into a normal 32-bit int range since 32-bit platforms are supported
388 if (resultTest > INT32_MAX || resultTest < INT32_MIN)
389 THROW_FMT(
390 FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
391 variantTypeName[varTypeInt]);
392
393 result = (int)resultTest;
394 break;
395 }
396
397 case varTypeString:
398 result = cvtZToInt(strZ(varStr(this)));
399 break;
400
401 case varTypeUInt:
402 {
403 unsigned int resultTest = varUInt(this);
404
405 // Make sure the value fits into a normal 32-bit int range
406 if (resultTest > INT32_MAX)
407 THROW_FMT(
408 FormatError, "unable to convert %s %u to %s", variantTypeName[varType(this)], resultTest,
409 variantTypeName[varTypeInt]);
410
411 result = (int)resultTest;
412 break;
413 }
414
415 case varTypeUInt64:
416 {
417 uint64_t resultTest = varUInt64(this);
418
419 // Make sure the value fits into a normal 32-bit int range
420 if (resultTest > INT32_MAX)
421 THROW_FMT(
422 FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
423 variantTypeName[varTypeInt]);
424
425 result = (int)resultTest;
426 break;
427 }
428
429 default:
430 THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeInt]);
431 }
432
433 FUNCTION_TEST_RETURN(result);
434 }
435
436 /**********************************************************************************************************************************/
437 Variant *
varNewInt64(int64_t data)438 varNewInt64(int64_t data)
439 {
440 FUNCTION_TEST_BEGIN();
441 FUNCTION_TEST_PARAM(INT64, data);
442 FUNCTION_TEST_END();
443
444 // Allocate memory for the variant and set the type and data
445 VariantInt64 *this = memNew(sizeof(VariantInt64));
446
447 *this = (VariantInt64)
448 {
449 .pub =
450 {
451 .type = varTypeInt64,
452 .data = data,
453 },
454 .memContext = memContextCurrent(),
455 };
456
457 FUNCTION_TEST_RETURN((Variant *)this);
458 }
459
460 /**********************************************************************************************************************************/
461 int64_t
varInt64(const Variant * this)462 varInt64(const Variant *this)
463 {
464 FUNCTION_TEST_BEGIN();
465 FUNCTION_TEST_PARAM(VARIANT, this);
466 FUNCTION_TEST_END();
467
468 ASSERT(this != NULL);
469 ASSERT(varType(this) == varTypeInt64);
470
471 FUNCTION_TEST_RETURN(((VariantInt64 *)this)->pub.data);
472 }
473
474 int64_t
varInt64Force(const Variant * this)475 varInt64Force(const Variant *this)
476 {
477 FUNCTION_TEST_BEGIN();
478 FUNCTION_TEST_PARAM(VARIANT, this);
479 FUNCTION_TEST_END();
480
481 ASSERT(this != NULL);
482
483 int64_t result = 0;
484
485 switch (varType(this))
486 {
487 case varTypeBool:
488 result = varBool(this);
489 break;
490
491 case varTypeInt:
492 result = (int64_t)varInt(this);
493 break;
494
495 case varTypeInt64:
496 result = varInt64(this);
497 break;
498
499 case varTypeString:
500 result = cvtZToInt64(strZ(varStr(this)));
501 break;
502
503 case varTypeUInt:
504 result = varUInt(this);
505
506 break;
507
508 case varTypeUInt64:
509 {
510 uint64_t resultTest = varUInt64(this);
511
512 // If max number of unsigned 64-bit integer is greater than max 64-bit signed integer can hold, then error
513 if (resultTest <= INT64_MAX)
514 result = (int64_t)resultTest;
515 else
516 {
517 THROW_FMT(
518 FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
519 variantTypeName[varTypeInt64]);
520 }
521
522 break;
523 }
524
525 default:
526 THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeInt64]);
527 }
528
529 FUNCTION_TEST_RETURN(result);
530 }
531
532 /**********************************************************************************************************************************/
533 Variant *
varNewUInt(unsigned int data)534 varNewUInt(unsigned int data)
535 {
536 FUNCTION_TEST_BEGIN();
537 FUNCTION_TEST_PARAM(UINT, data);
538 FUNCTION_TEST_END();
539
540 // Allocate memory for the variant and set the type and data
541 VariantUInt *this = memNew(sizeof(VariantUInt));
542
543 *this = (VariantUInt)
544 {
545 .pub =
546 {
547 .type = varTypeUInt,
548 .data = data,
549 },
550 .memContext = memContextCurrent(),
551 };
552
553 FUNCTION_TEST_RETURN((Variant *)this);
554 }
555
556 /**********************************************************************************************************************************/
557 unsigned int
varUInt(const Variant * this)558 varUInt(const Variant *this)
559 {
560 FUNCTION_TEST_BEGIN();
561 FUNCTION_TEST_PARAM(VARIANT, this);
562 FUNCTION_TEST_END();
563
564 ASSERT(this != NULL);
565 ASSERT(varType(this) == varTypeUInt);
566
567 FUNCTION_TEST_RETURN(((VariantUInt *)this)->pub.data);
568 }
569
570 unsigned int
varUIntForce(const Variant * this)571 varUIntForce(const Variant *this)
572 {
573 FUNCTION_TEST_BEGIN();
574 FUNCTION_TEST_PARAM(VARIANT, this);
575 FUNCTION_TEST_END();
576
577 ASSERT(this != NULL);
578
579 unsigned int result = 0;
580
581 switch (varType(this))
582 {
583 case varTypeBool:
584 result = varBool(this);
585 break;
586
587 case varTypeInt:
588 {
589 int resultTest = varInt(this);
590
591 // If integer is a negative number, throw an error since the resulting conversion would be a different number
592 if (resultTest >= 0)
593 result = (unsigned int)resultTest;
594 else
595 {
596 THROW_FMT(
597 FormatError, "unable to convert %s %d to %s", variantTypeName[varType(this)], resultTest,
598 variantTypeName[varTypeUInt]);
599 }
600
601 break;
602 }
603
604 case varTypeInt64:
605 {
606 int64_t resultTest = varInt64(this);
607
608 // If integer is a negative number or too large, throw an error since the resulting conversion would be out of bounds
609 if (resultTest >= 0 && resultTest <= UINT_MAX)
610 result = (unsigned int)resultTest;
611 else
612 {
613 THROW_FMT(
614 FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
615 variantTypeName[varTypeUInt]);
616 }
617
618 break;
619 }
620
621 case varTypeUInt:
622 result = varUInt(this);
623 break;
624
625 case varTypeUInt64:
626 {
627 uint64_t resultTest = varUInt64(this);
628
629 // If integer is too large, throw an error since the resulting conversion would be out of bounds
630 if (resultTest <= UINT_MAX)
631 result = (unsigned int)resultTest;
632 else
633 {
634 THROW_FMT(
635 FormatError, "unable to convert %s %" PRIu64 " to %s", variantTypeName[varType(this)], resultTest,
636 variantTypeName[varTypeUInt]);
637 }
638
639 break;
640 }
641
642 case varTypeString:
643 result = cvtZToUInt(strZ(varStr(this)));
644 break;
645
646 default:
647 THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeUInt]);
648 }
649
650 FUNCTION_TEST_RETURN(result);
651 }
652
653 /**********************************************************************************************************************************/
654 Variant *
varNewUInt64(uint64_t data)655 varNewUInt64(uint64_t data)
656 {
657 FUNCTION_TEST_BEGIN();
658 FUNCTION_TEST_PARAM(UINT64, data);
659 FUNCTION_TEST_END();
660
661 // Allocate memory for the variant and set the type and data
662 VariantUInt64 *this = memNew(sizeof(VariantUInt64));
663
664 *this = (VariantUInt64)
665 {
666 .pub =
667 {
668 .type = varTypeUInt64,
669 .data = data,
670 },
671 .memContext = memContextCurrent(),
672 };
673
674 FUNCTION_TEST_RETURN((Variant *)this);
675 }
676
677 /**********************************************************************************************************************************/
678 uint64_t
varUInt64(const Variant * this)679 varUInt64(const Variant *this)
680 {
681 FUNCTION_TEST_BEGIN();
682 FUNCTION_TEST_PARAM(VARIANT, this);
683 FUNCTION_TEST_END();
684
685 ASSERT(this != NULL);
686 ASSERT(varType(this) == varTypeUInt64);
687
688 FUNCTION_TEST_RETURN(((VariantUInt64 *)this)->pub.data);
689 }
690
691 uint64_t
varUInt64Force(const Variant * this)692 varUInt64Force(const Variant *this)
693 {
694 FUNCTION_TEST_BEGIN();
695 FUNCTION_TEST_PARAM(VARIANT, this);
696 FUNCTION_TEST_END();
697
698 ASSERT(this != NULL);
699
700 uint64_t result = 0;
701
702 switch (varType(this))
703 {
704 case varTypeBool:
705 result = varBool(this);
706 break;
707
708 case varTypeInt:
709 {
710 int resultTest = varInt(this);
711
712 // If integer is a negative number, throw an error since the resulting conversion would be a different number
713 if (resultTest >= 0)
714 result = (uint64_t)resultTest;
715 else
716 {
717 THROW_FMT(
718 FormatError, "unable to convert %s %d to %s", variantTypeName[varType(this)], resultTest,
719 variantTypeName[varTypeUInt64]);
720 }
721
722 break;
723 }
724
725 case varTypeInt64:
726 {
727 int64_t resultTest = varInt64(this);
728
729 // If integer is a negative number, throw an error since the resulting conversion would be out of bounds
730 if (resultTest >= 0)
731 result = (uint64_t)resultTest;
732 else
733 {
734 THROW_FMT(
735 FormatError, "unable to convert %s %" PRId64 " to %s", variantTypeName[varType(this)], resultTest,
736 variantTypeName[varTypeUInt64]);
737 }
738
739 break;
740 }
741
742 case varTypeString:
743 result = cvtZToUInt64(strZ(varStr(this)));
744 break;
745
746 case varTypeUInt:
747 result = varUInt(this);
748 break;
749
750 case varTypeUInt64:
751 result = varUInt64(this);
752 break;
753
754 default:
755 THROW_FMT(AssertError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeUInt64]);
756 }
757
758 FUNCTION_TEST_RETURN(result);
759 }
760
761 /**********************************************************************************************************************************/
762 Variant *
varNewKv(KeyValue * data)763 varNewKv(KeyValue *data)
764 {
765 FUNCTION_TEST_BEGIN();
766 FUNCTION_TEST_PARAM(KEY_VALUE, data);
767 FUNCTION_TEST_END();
768
769 // Allocate memory for the variant and set the type and data
770 VariantKeyValue *this = memNew(sizeof(VariantKeyValue));
771
772 *this = (VariantKeyValue)
773 {
774 .memContext = memContextCurrent(),
775 .type = varTypeKeyValue,
776 };
777
778 if (data != NULL)
779 this->data = kvMove(data, memContextCurrent());
780
781 FUNCTION_TEST_RETURN((Variant *)this);
782 }
783
784 /**********************************************************************************************************************************/
785 KeyValue *
varKv(const Variant * this)786 varKv(const Variant *this)
787 {
788 FUNCTION_TEST_BEGIN();
789 FUNCTION_TEST_PARAM(VARIANT, this);
790 FUNCTION_TEST_END();
791
792 KeyValue *result = NULL;
793
794 if (this != NULL)
795 {
796 ASSERT(varType(this) == varTypeKeyValue);
797 result = ((VariantKeyValue *)this)->data;
798 }
799
800 FUNCTION_TEST_RETURN(result);
801 }
802
803 /**********************************************************************************************************************************/
804 Variant *
varNewStr(const String * data)805 varNewStr(const String *data)
806 {
807 FUNCTION_TEST_BEGIN();
808 FUNCTION_TEST_PARAM(STRING, data);
809 FUNCTION_TEST_END();
810
811 // Allocate memory for the variant and set the type and data
812 VariantString *this = memNew(sizeof(VariantString));
813
814 *this = (VariantString)
815 {
816 .pub =
817 {
818 .type = varTypeString,
819 .data = strDup(data),
820 },
821 .memContext = memContextCurrent(),
822 };
823
824 FUNCTION_TEST_RETURN((Variant *)this);
825 }
826
827 Variant *
varNewStrZ(const char * data)828 varNewStrZ(const char *data)
829 {
830 FUNCTION_TEST_BEGIN();
831 FUNCTION_TEST_PARAM(STRINGZ, data);
832 FUNCTION_TEST_END();
833
834 FUNCTION_TEST_RETURN(varNewStr(data == NULL ? NULL : strNewZ(data)));
835 }
836
837 /**********************************************************************************************************************************/
838 const String *
varStr(const Variant * this)839 varStr(const Variant *this)
840 {
841 FUNCTION_TEST_BEGIN();
842 FUNCTION_TEST_PARAM(VARIANT, this);
843 FUNCTION_TEST_END();
844
845 String *result = NULL;
846
847 if (this != NULL)
848 {
849 ASSERT(varType(this) == varTypeString);
850 result = ((VariantString *)this)->pub.data;
851 }
852
853 FUNCTION_TEST_RETURN(result);
854 }
855
856 String *
varStrForce(const Variant * this)857 varStrForce(const Variant *this)
858 {
859 FUNCTION_TEST_BEGIN();
860 FUNCTION_TEST_PARAM(VARIANT, this);
861 FUNCTION_TEST_END();
862
863 ASSERT(this != NULL);
864
865 String *result = NULL;
866
867 switch (varType(this))
868 {
869 case varTypeBool:
870 result = strNewZ(cvtBoolToConstZ(varBool(this)));
871 break;
872
873 case varTypeInt:
874 {
875 char working[CVT_BASE10_BUFFER_SIZE];
876
877 cvtIntToZ(varInt(this), working, sizeof(working));
878 result = strNewZ(working);
879 break;
880 }
881
882 case varTypeInt64:
883 {
884 char working[CVT_BASE10_BUFFER_SIZE];
885
886 cvtInt64ToZ(varInt64(this), working, sizeof(working));
887 result = strNewZ(working);
888 break;
889 }
890
891 case varTypeString:
892 result = strDup(varStr(this));
893 break;
894
895 case varTypeUInt:
896 {
897 char working[CVT_BASE10_BUFFER_SIZE];
898
899 cvtUIntToZ(varUInt(this), working, sizeof(working));
900 result = strNewZ(working);
901 break;
902 }
903
904 case varTypeUInt64:
905 {
906 char working[CVT_BASE10_BUFFER_SIZE];
907
908 cvtUInt64ToZ(varUInt64(this), working, sizeof(working));
909 result = strNewZ(working);
910 break;
911 }
912
913 default:
914 THROW_FMT(FormatError, "unable to force %s to %s", variantTypeName[varType(this)], variantTypeName[varTypeString]);
915 }
916
917 FUNCTION_TEST_RETURN(result);
918 }
919
920 /**********************************************************************************************************************************/
921 Variant *
varNewVarLst(const VariantList * data)922 varNewVarLst(const VariantList *data)
923 {
924 FUNCTION_TEST_BEGIN();
925 FUNCTION_TEST_PARAM(VARIANT_LIST, data);
926 FUNCTION_TEST_END();
927
928 // Allocate memory for the variant and set the type and data
929 VariantVariantList *this = memNew(sizeof(VariantVariantList));
930
931 *this = (VariantVariantList)
932 {
933 .memContext = memContextCurrent(),
934 .type = varTypeVariantList,
935 };
936
937 if (data != NULL)
938 this->data = varLstDup(data);
939
940 FUNCTION_TEST_RETURN((Variant *)this);
941 }
942
943 /**********************************************************************************************************************************/
944 VariantList *
varVarLst(const Variant * this)945 varVarLst(const Variant *this)
946 {
947 FUNCTION_TEST_BEGIN();
948 FUNCTION_TEST_PARAM(VARIANT, this);
949 FUNCTION_TEST_END();
950
951 VariantList *result = NULL;
952
953 if (this != NULL)
954 {
955 ASSERT(varType(this) == varTypeVariantList);
956 result = ((VariantVariantList *)this)->data;
957 }
958
959 FUNCTION_TEST_RETURN(result);
960 }
961
962 /**********************************************************************************************************************************/
963 String *
varToLog(const Variant * this)964 varToLog(const Variant *this)
965 {
966 String *result = NULL;
967
968 if (this == NULL)
969 result = strDup(NULL_STR);
970 else
971 {
972 switch (varType(this))
973 {
974 case varTypeString:
975 result = strToLog(varStr(this));
976 break;
977
978 case varTypeKeyValue:
979 result = strNewZ("{KeyValue}");
980 break;
981
982 case varTypeVariantList:
983 result = strNewZ("{VariantList}");
984 break;
985
986 case varTypeBool:
987 case varTypeInt:
988 case varTypeInt64:
989 case varTypeUInt:
990 case varTypeUInt64:
991 {
992 result = strNewFmt("{%s}", strZ(varStrForce(this)));
993 break;
994 }
995 }
996 }
997
998 return result;
999 }
1000
1001 /**********************************************************************************************************************************/
1002 void
varFree(Variant * this)1003 varFree(Variant *this)
1004 {
1005 FUNCTION_TEST_BEGIN();
1006 FUNCTION_TEST_PARAM(VARIANT, this);
1007 FUNCTION_TEST_END();
1008
1009 if (this != NULL)
1010 {
1011 MemContext *memContext = NULL;
1012
1013 switch (varType(this))
1014 {
1015 case varTypeBool:
1016 memContext = ((VariantBool *)this)->memContext;
1017 break;
1018
1019 case varTypeInt:
1020 memContext = ((VariantInt *)this)->memContext;
1021 break;
1022
1023 case varTypeInt64:
1024 memContext = ((VariantInt64 *)this)->memContext;
1025 break;
1026
1027 case varTypeKeyValue:
1028 memContext = ((VariantKeyValue *)this)->memContext;
1029 kvFree(((VariantKeyValue *)this)->data);
1030 break;
1031
1032 case varTypeString:
1033 memContext = ((VariantString *)this)->memContext;
1034 strFree(((VariantString *)this)->pub.data);
1035 break;
1036
1037 case varTypeUInt:
1038 memContext = ((VariantUInt *)this)->memContext;
1039 break;
1040
1041 case varTypeUInt64:
1042 memContext = ((VariantUInt64 *)this)->memContext;
1043 break;
1044
1045 case varTypeVariantList:
1046 memContext = ((VariantVariantList *)this)->memContext;
1047 varLstFree(((VariantVariantList *)this)->data);
1048 break;
1049 }
1050
1051 MEM_CONTEXT_BEGIN(memContext)
1052 {
1053 memFree(this);
1054 }
1055 MEM_CONTEXT_END();
1056 }
1057
1058 FUNCTION_TEST_RETURN_VOID();
1059 }
1060