1 /++
2 $(H1 Mutable Ion value with IonNull support)
3 
4 This module contains a single alias definition and doesn't provide Ion serialization API.
5 
6 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0)
7 Authors: Ilia Ki 
8 Macros:
9 +/
10 module mir.algebraic_alias.ion_ext;
11 
12 import mir.algebraic: Algebraic, This;
13 public import mir.annotated: Annotated;
14 public import mir.ion.value: IonNull;
15 public import mir.ion.type_code: IonTypeCode;
16 public import mir.lob: Clob, Blob;
17 public import mir.string_map: StringMap;
18 public import mir.timestamp: Timestamp;
19 
20 
21 /++
22 Definition union for $(LREF IonExtAlgebraic).
23 +/
24 union IonExt_
25 {
26     ///
27     IonNull null_;
28     ///
29     bool boolean;
30     ///
31     long integer;
32     ///
33     double float_;
34     ///
35     immutable(char)[] string;
36     ///
37     Blob blob;
38     ///
39     Clob clob;
40     ///
41     Timestamp timestamp;
42     /// Self alias in array.
43     This[] array;
44     /// Self alias in $(MREF mir,string_map).
45     StringMap!This object;
46     /// Self alias in $(MREF mir,annotated).
47     Annotated!This annotated;
48 }
49 
50 /++
51 Ion tagged algebraic alias.
52 
53 The example below shows only the basic features. Advanced API to work with algebraic types can be found at $(GMREF mir-core, mir,algebraic).
54 See also $(MREF mir,string_map) - ordered string-value associative array.
55 +/
56 alias IonExtAlgebraic = Algebraic!IonExt_;
57 
58 ///
59 @safe pure
60 unittest
61 {
62     import mir.ndslice.topology: map;
63     import mir.array.allocation: array;
64 
65     IonExtAlgebraic value;
66 
67     StringMap!IonExtAlgebraic object;
68 
69     // Default
70     assert(value._is!IonNull);
71     assert(value.get!IonNull == IonTypeCode.null_.IonNull);
72     assert(value.kind == IonExtAlgebraic.Kind.null_);
73 
74     // Boolean
75     value = object["bool"] = true;
76     assert(value == true);
77     assert(value.kind == IonExtAlgebraic.Kind.boolean);
78     // access
79     assert(value.boolean == true);
80     assert(value.get!bool == true);
81     assert(value.get!"boolean" == true);
82     assert(value.get!(IonExtAlgebraic.Kind.boolean) == true);
83     // nothrow access
84     assert(value.trustedGet!bool == true);
85     assert(value.trustedGet!"boolean" == true);
86     assert(value.trustedGet!(IonExtAlgebraic.Kind.boolean) == true);
87     // checks
88     assert(!value._is!string);
89     assert(value._is!bool);
90     assert(value._is!"boolean");
91     assert(value._is!(IonExtAlgebraic.Kind.boolean));
92 
93     // Null
94     value = object["null"] = IonTypeCode..string.IonNull;
95     assert(value._is!IonNull);
96     assert(value == IonTypeCode..string.IonNull);
97     assert(value.kind == IonExtAlgebraic.Kind.null_);
98     assert(value.null_ == IonTypeCode..string.IonNull);
99     assert(value.get!IonNull == IonTypeCode..string.IonNull);
100     assert(value.get!(IonExtAlgebraic.Kind.null_) == IonTypeCode..string.IonNull);
101 
102     // String
103     value = object["string"] = "s";
104     assert(value.kind == IonExtAlgebraic.Kind..string);
105     assert(value == "s");
106     // access
107     // Yep, `string` here is an alias to `get!(immutable(char)[])` method
108     assert(value..string == "s");
109     // `string` here is an alias of type `immutable(char)[]`
110     assert(value.get!string == "s");
111     assert(value.get!"string" == "s");
112     // finally, `string` here is an enum meber
113     assert(value.get!(IonExtAlgebraic.Kind..string) == "s");
114 
115     // Integer
116     value = object["integer"] = 4;
117     assert(value.kind == IonExtAlgebraic.Kind.integer);
118     assert(value == 4);
119     assert(value != 4.0);
120     assert(value.integer == 4);
121 
122     // Float
123     value = object["float"] = 3.0;
124     assert(value.kind == IonExtAlgebraic.Kind.float_);
125     assert(value != 3);
126     assert(value == 3.0);
127     assert(value.float_ == 3.0);
128 
129     // Array
130     IonExtAlgebraic[] arr = [0, 1, 2, 3, 4].map!IonExtAlgebraic.array;
131 
132     value = object["array"] = arr;
133     assert(value.kind == IonExtAlgebraic.Kind.array);
134     assert(value == arr);
135     assert(value == [0, 1, 2, 3, 4].map!IonExtAlgebraic.array);
136     assert(value.array[3] == 3);
137 
138     // Object
139     assert(object.keys == ["bool", "null", "string", "integer", "float", "array"]);
140     object.values[0] = "false";
141     assert(object["bool"] == "false"); // it is a string now
142     object.remove("bool"); // remove the member
143 
144     value = object["array"] = object;
145     assert(value.kind == IonExtAlgebraic.Kind.object);
146     assert(value.object.keys is object.keys);
147 
148     IonExtAlgebraic[string] aa = object.toAA;
149     object = aa.StringMap!IonExtAlgebraic;
150 
151     IonExtAlgebraic fromAA = ["a" : IonExtAlgebraic(3), "b" : IonExtAlgebraic("b")];
152     assert(fromAA.object["a"] == 3);
153     assert(fromAA.object["b"] == "b");
154 
155     auto annotated = Annotated!IonExtAlgebraic(["birthday"], Timestamp("2001-01-01"));
156     value = annotated;
157     assert(value == annotated);
158     value = annotated.IonExtAlgebraic;
159     assert(value == annotated);
160 }