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
(
string suffixToStrip = "Settings"
Range
Things...
)
(
auto ref Range range
,
out string[][string] missingEntries
,
out string[][string] invalidEntries
,
ref Things things
)

Parameters

suffixToStrip

Substring to strip off the end of struct names when reading them from the input range. Defaults to "Settings". May be empty.

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     {
64 
65         FooSettings foo;
66         serialisedFileContents
67             .splitter("\n")
68             .deserialise(missing, invalid, foo);
69 
70         with (foo)
71         {
72             import std.math : isClose;
73 
74             assert((i == 42), i.text);
75             assert((ia == [ 1, 2, -3, 4, 5 ]), ia.text);
76             assert((s == "hello world!"), s);
77             assert((sa == [ "hello", "world", "!" ]), sa.text);
78             assert(b);
79             assert((ba == [ true, false, true ]), ba.text);
80             assert((f == 3.14f), f.text);
81             assert((fa == [ 0.0f, 1.1f, -2.2f, 3.3f ]), fa.text);
82             assert((d == 99.9), d.text);
83 
84             // rounding errors with LDC on Windows
85             assert(da[0].isClose(99.9999), da[0].text);
86             assert(da[1].isClose(0.0001), da[1].text);
87             assert(da[2].isClose(-1.0), da[2].text);
88 
89             with (FooSettings.Bar)
90             {
91                 assert((bar == oorgle), bar.text);
92                 assert((bara == [ blaawp, oorgle, blaawp ]), bara.text);
93             }
94         }
95 
96         import std.algorithm.searching : canFind;
97 
98         assert("Foo" in missing);
99         assert(missing["Foo"].canFind("missing"));
100         assert(!missing["Foo"].canFind("commented"));
101         assert(!missing["Foo"].canFind("slashed"));
102         assert("Foo" in invalid);
103         assert(invalid["Foo"].canFind("invalid"));
104     }
105     {
106         struct DifferentSection
107         {
108             string ignored;
109             string because;
110             int nil;
111             string naN;
112         }
113 
114         // Can read other structs from the same file
115 
116         DifferentSection diff;
117         serialisedFileContents
118             .splitter("\n")
119             .deserialise(missing, invalid, diff);
120 
121         with (diff)
122         {
123             assert((ignored == "completely"), ignored);
124             assert((because == "no DifferentSection struct was passed"), because);
125             assert((nil == 5), nil.text);
126             assert((naN == `!"¤%&/`), naN);
127         }
128     }
129     {
130         enum Letters { abc, def, ghi }
131 
132         struct StructWithSuffixToStrip
133         {
134             Letters lt = Letters.def;
135         }
136 
137         enum configContents =
138 `[Struct]
139 lt ghi
140 `;
141         StructWithSuffixToStrip st;
142         configContents
143             .splitter("\n")
144             .deserialise!("WithSuffixToStrip")(missing, invalid, st);
145 
146         assert(st.lt == Letters.ghi);
147     }
148     {
149         class Class
150         {
151             enum Bar { blaawp = 5, oorgle = -1 }
152             int i;
153             string s;
154             bool b;
155             float f;
156             double d;
157             Bar bar;
158             string omitted;
159 
160             @Separator(",")
161             {
162                 int[] ia;
163                 string[] sa;
164                 bool[] ba;
165                 float[] fa;
166                 double[] da;
167                 Bar[] bara;
168             }
169         }
170 
171         enum serialisedFileContentsClass =
172 `[Class]
173 i       42
174 ia      1,2,-3,4,5
175 s       hello world!
176 sa      hello,world,!
177 b       true
178 ba      true,false,true
179 wrong   name
180 
181 # comment
182 ; other type of comment
183 // third type of comment
184 
185 f       3.14 #hirp
186 fa      0.0,1.1,-2.2,3.3 ;herp
187 d       99.9 //derp
188 da      99.9999,0.0001,-1
189 bar     oorgle
190 bara    blaawp,oorgle,blaawp`;
191 
192         Class c = new Class;
193         serialisedFileContentsClass
194             .splitter("\n")
195             .deserialise(missing, invalid, c);
196 
197         with (c)
198         {
199             import std.math : isClose;
200 
201             assert((i == 42), i.text);
202             assert((ia == [ 1, 2, -3, 4, 5 ]), ia.text);
203             assert((s == "hello world!"), s);
204             assert((sa == [ "hello", "world", "!" ]), sa.text);
205             assert(b);
206             assert((ba == [ true, false, true ]), ba.text);
207             assert((f == 3.14f), f.text);
208             assert((fa == [ 0.0f, 1.1f, -2.2f, 3.3f ]), fa.text);
209             assert((d == 99.9), d.text);
210 
211             // rounding errors with LDC on Windows
212             assert(da[0].isClose(99.9999), da[0].text);
213             assert(da[1].isClose(0.0001), da[1].text);
214             assert(da[2].isClose(-1.0), da[2].text);
215 
216             with (Class.Bar)
217             {
218                 assert((bar == oorgle), b.text);
219                 assert((bara == [ blaawp, oorgle, blaawp ]), bara.text);
220             }
221         }
222     }