deserialise

Takes an input range containing serialised entry-value text and applies the contents therein to one or more passed struct/class objects.

@safe pure
void
deserialise
(
Range
Things...
)
(
auto ref Range range
,
out string[][string] missingEntries
,
out string[][string] invalidEntries
,
ref Things things
)

Parameters

range Range

Input range from which to read the serialised text.

missingEntries string[][string]

Out reference of an associative array of string arrays of expected entries that were missing.

invalidEntries string[][string]

Out reference of an associative array of string arrays of unexpected entries that did not belong.

things Things

Reference variadic list of one or more objects to apply the deserialised values to.

Throws

DeserialisationException if there were bad lines.

Examples

struct Foo
{
    // ...
}

struct Bar
{
    // ...
}

Foo foo;
Bar bar;

string[][string] missingEntries;
string[][string] invalidEntries;

string fromFile = readText("configuration.conf");

fromFile
    .splitter("\n")
    .deserialise(missingEntries, invalidEntries, foo, bar);
1     import lu.uda : Separator;
2     import std.algorithm.iteration : splitter;
3     import std.conv : text;
4 
5     struct FooSettings
6     {
7         enum Bar { blaawp = 5, oorgle = -1 }
8         int i;
9         string s;
10         bool b;
11         float f;
12         double d;
13         Bar bar;
14         string commented;
15         string slashed;
16         int missing;
17         //bool invalid;
18 
19         @Separator(",")
20         {
21             int[] ia;
22             string[] sa;
23             bool[] ba;
24             float[] fa;
25             double[] da;
26             Bar[] bara;
27         }
28     }
29 
30     enum serialisedFileContents =
31 `[Foo]
32 i       42
33 ia      1,2,-3,4,5
34 s       hello world!
35 sa      hello,world,!
36 b       true
37 ba      true,false,true
38 invalid name
39 
40 # comment
41 ; other type of comment
42 // third type of comment
43 
44 f       3.14 #hirp
45 fa      0.0,1.1,-2.2,3.3 ;herp
46 d       99.9 //derp
47 da      99.9999,0.0001,-1
48 bar     oorgle
49 bara    blaawp,oorgle,blaawp
50 #commented hi
51 // slashed also commented
52 invalid ho
53 
54 [DifferentSection]
55 ignored completely
56 because no DifferentSection struct was passed
57 nil     5
58 naN     !"¤%&/`;
59 
60     string[][string] missing;
61     string[][string] invalid;
62 
63     FooSettings foo;
64     serialisedFileContents
65         .splitter("\n")
66         .deserialise(missing, invalid, foo);
67 
68     with (foo)
69     {
70         assert((i == 42), i.text);
71         assert((ia == [ 1, 2, -3, 4, 5 ]), ia.text);
72         assert((s == "hello world!"), s);
73         assert((sa == [ "hello", "world", "!" ]), sa.text);
74         assert(b);
75         assert((ba == [ true, false, true ]), ba.text);
76         assert((f == 3.14f), f.text);
77         assert((fa == [ 0.0f, 1.1f, -2.2f, 3.3f ]), fa.text);
78         assert((d == 99.9), d.text);
79 
80         static if (__VERSION__ >= 2091)
81         {
82             import std.math : isClose;
83         }
84         else
85         {
86             import std.math : approxEqual;
87             alias isClose = approxEqual;
88         }
89 
90         // rounding errors with LDC on Windows
91         assert(isClose(da[0], 99.9999), da[0].text);
92         assert(isClose(da[1], 0.0001), da[1].text);
93         assert(isClose(da[2], -1.0), da[2].text);
94 
95         with (FooSettings.Bar)
96         {
97             assert((bar == oorgle), bar.text);
98             assert((bara == [ blaawp, oorgle, blaawp ]), bara.text);
99         }
100     }
101 
102     import std.algorithm.searching : canFind;
103 
104     assert("Foo" in missing);
105     assert(missing["Foo"].canFind("missing"));
106     assert(!missing["Foo"].canFind("commented"));
107     assert(!missing["Foo"].canFind("slashed"));
108     assert("Foo" in invalid);
109     assert(invalid["Foo"].canFind("invalid"));
110 
111     struct DifferentSection
112     {
113         string ignored;
114         string because;
115         int nil;
116         string naN;
117     }
118 
119     // Can read other structs from the same file
120 
121     DifferentSection diff;
122     serialisedFileContents
123         .splitter("\n")
124         .deserialise(missing, invalid, diff);
125 
126     with (diff)
127     {
128         assert((ignored == "completely"), ignored);
129         assert((because == "no DifferentSection struct was passed"), because);
130         assert((nil == 5), nil.text);
131         assert((naN == `!"¤%&/`), naN);
132     }
133 
134     enum Letters { abc, def, ghi, }
135 
136     struct Struct
137     {
138         Letters lt = Letters.def;
139     }
140 
141     enum configContents =
142 `[Struct]
143 lt ghi
144 `;
145     Struct st;
146     configContents
147         .splitter("\n")
148         .deserialise(missing, invalid, st);
149 
150     assert(st.lt == Letters.ghi);
151 
152     class Class
153     {
154         enum Bar { blaawp = 5, oorgle = -1 }
155         int i;
156         string s;
157         bool b;
158         float f;
159         double d;
160         Bar bar;
161         string omitted;
162 
163         @Separator(",")
164         {
165             int[] ia;
166             string[] sa;
167             bool[] ba;
168             float[] fa;
169             double[] da;
170             Bar[] bara;
171         }
172     }
173 
174     enum serialisedFileContentsClass =
175 `[Class]
176 i       42
177 ia      1,2,-3,4,5
178 s       hello world!
179 sa      hello,world,!
180 b       true
181 ba      true,false,true
182 wrong   name
183 
184 # comment
185 ; other type of comment
186 // third type of comment
187 
188 f       3.14 #hirp
189 fa      0.0,1.1,-2.2,3.3 ;herp
190 d       99.9 //derp
191 da      99.9999,0.0001,-1
192 bar     oorgle
193 bara    blaawp,oorgle,blaawp`;
194 
195     Class c = new Class;
196     serialisedFileContentsClass
197         .splitter("\n")
198         .deserialise(missing, invalid, c);
199 
200     with (c)
201     {
202         assert((i == 42), i.text);
203         assert((ia == [ 1, 2, -3, 4, 5 ]), ia.text);
204         assert((s == "hello world!"), s);
205         assert((sa == [ "hello", "world", "!" ]), sa.text);
206         assert(b);
207         assert((ba == [ true, false, true ]), ba.text);
208         assert((f == 3.14f), f.text);
209         assert((fa == [ 0.0f, 1.1f, -2.2f, 3.3f ]), fa.text);
210         assert((d == 99.9), d.text);
211 
212         static if (__VERSION__ >= 2091)
213         {
214             import std.math : isClose;
215         }
216         else
217         {
218             import std.math : approxEqual;
219             alias isClose = approxEqual;
220         }
221 
222         // rounding errors with LDC on Windows
223         assert(isClose(da[0], 99.9999), da[0].text);
224         assert(isClose(da[1], 0.0001), da[1].text);
225         assert(isClose(da[2], -1.0), da[2].text);
226 
227         with (Class.Bar)
228         {
229             assert((bar == oorgle), b.text);
230             assert((bara == [ blaawp, oorgle, blaawp ]), bara.text);
231         }
232     }