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 }