The OpenD Programming Language

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