1 module toml_foolery.encode.types.table;
2 
3 import std.traits : isAssociativeArray, KeyType, isSomeString, FieldNameTuple;
4 
5 import toml_foolery.attributes.toml_name;
6 import toml_foolery.encode;
7 import toml_foolery.encode.tomlify;
8 import toml_foolery.encode.types.datetime :
9     makesTomlOffsetDateTime,
10     makesTomlLocalDateTime,
11     makesTomlLocalTime,
12     makesTomlLocalDate;
13 
14 version(unittest) import toml_foolery.encode.util : expectToEqualNoBlanks;
15 
16 
17 private enum bool isSpeciallyHandledStruct(T) = (
18     makesTomlLocalDate!T ||
19     makesTomlLocalTime!T ||
20     makesTomlLocalDateTime!T ||
21     makesTomlOffsetDateTime!T
22 );
23 
24 package(toml_foolery.encode) enum bool makesTomlTable(T) = (
25     is(T == struct) &&
26     !isSpeciallyHandledStruct!T
27 );
28 
29 /// Serializes structs into TOML tables.
30 package(toml_foolery.encode) void tomlifyValueImpl(T)(
31     const T value,
32     ref Appender!string buffer,
33     immutable string[] parentTables
34 )
35 if (makesTomlTable!T)
36 {
37     enum auto fieldNames = FieldNameTuple!T;
38 
39     static assert (
40         !hasDuplicateKeys!T,
41         "Struct " ~ T.stringof ~ "contains some duplicate key names."
42     );
43 
44     static foreach (fieldName; fieldNames)
45     {
46         tomlifyField(dFieldToTomlKey!(T, fieldName), __traits(getMember, value, fieldName), buffer, parentTables);
47     }
48 }
49 
50 @("Encode a struct with no fields")
51 unittest
52 {
53     struct Empty { }
54 
55     Empty s;
56 
57     expectToEqualNoBlanks(_tomlifyValue(s), ``);
58 }
59 
60 @("Encode a struct with some fields")
61 unittest
62 {
63     struct Example
64     {
65         int i;
66         float f;
67         string s;
68     }
69 
70     Example sInit;
71 
72     expectToEqualNoBlanks(_tomlifyValue(sInit), `
73     i = 0
74     f = nan
75     s = ""
76     `);
77 
78     Example sCustom = Example(225, -5.0f, "kwyjibo");
79 
80     expectToEqualNoBlanks(_tomlifyValue(sCustom), `
81     i = 225
82     f = -5.0
83     s = "kwyjibo"
84     `);
85 }
86 
87 @("All that we see or seem is but a struct within a struct")
88 unittest
89 {
90     struct Position
91     {
92         int x;
93         int y;
94     }
95 
96     struct Entity
97     {
98         string name;
99         Position pos;
100     }
101 
102     Entity e = Entity("Simon?", Position(-22, 95));
103 
104     expectToEqualNoBlanks(_tomlifyValue(e), `
105         name = "Simon?"
106 
107         [pos]
108         x = -22
109         y = 95
110         `);
111 }
112 
113 @("Yo Dawg, I herd you like structs.")
114 unittest
115 {
116     struct Inner
117     {
118         int c;
119     }
120 
121     struct Middle
122     {
123         int b;
124         Inner inn;
125     }
126 
127     struct Outer
128     {
129         int a;
130         Middle mid;
131     }
132 
133     Outer s = Outer();
134 
135     expectToEqualNoBlanks(_tomlifyValue(s), `
136         a = 0
137 
138         [mid]
139         b = 0
140 
141         [mid.inn]
142         c = 0
143         `);
144 }
145 
146 @("Structs all the way down")
147 unittest
148 {
149     struct L5
150     {
151         int f;
152     }
153 
154     struct L4
155     {
156         int e;
157         L5 me;
158     }
159 
160     struct L3
161     {
162         int d;
163         L4 told;
164     }
165 
166     struct L2
167     {
168         int c;
169         L3 once;
170     }
171 
172     struct L1
173     {
174         int b;
175         L2 body;
176     }
177 
178     struct L0
179     {
180         int a;
181         L1 some;
182     }
183 
184     L0 l;
185 
186     expectToEqualNoBlanks(_tomlifyValue(l), `
187         a = 0
188 
189         [some]
190         b = 0
191 
192         [some.body]
193         c = 0
194 
195         [some.body.once]
196         d = 0
197 
198         [some.body.once.told]
199         e = 0
200 
201         [some.body.once.told.me]
202         f = 0
203         `);
204 }
205 
206 
207 @("Encode tables whose names must be quoted")
208 unittest
209 {
210     struct A
211     {
212         int x;
213     }
214 
215     struct B
216     {
217         int y;
218         A ш;
219     }
220 
221     struct C
222     {
223         int z;
224         B normal;
225     }
226 
227     expectToEqualNoBlanks(_tomlifyValue(C()), `
228     z = 0
229 
230     [normal]
231     y = 0
232 
233     [normal."ш"]
234     x = 0
235     `);
236 
237 }