1 module toml_foolery.encode.types.integer;
2 
3 import std.traits : isIntegral;
4 import std.uni : isNumber;
5 
6 import toml_foolery.encode;
7 
8 
9 package(toml_foolery.encode) enum bool makesTomlInteger(T) = (
10     isIntegral!T && !(is(T == enum))
11 );
12 
13 
14 /// Serializes integral types into TOML Integer values.
15 /// Throws:
16 ///     TomlEncodingException when value is out of range of valid TOML Integers
17 ///     (can only happen when T is `ulong`).
18 package(toml_foolery.encode) void tomlifyValueImpl(T)(
19     const T value,
20     ref Appender!string buffer,
21     immutable string[] parentTables
22 )
23 if (makesTomlInteger!T)
24 {
25     static if (is(T == ulong))
26     {
27         if (value > long.max.to!ulong)
28         {
29             throw new TomlEncodingException(
30                 "ulong value is out of TOML integer range (-2^63, 2^63 - 1): " ~ value.to!string
31             );
32         }
33     }
34 
35     string valueStr = value.to!string;
36     if (
37         (valueStr.length >= 5 && valueStr[0].isNumber) ||
38         (valueStr.length >= 6)
39     )
40     {
41         valueStr = "%,?d".format('_', value);
42     }
43     else
44     {
45         valueStr = "%d".format(value);
46     }
47 
48     buffer.put(valueStr);
49 }
50 
51 
52 @("Encode `byte` fields")
53 unittest
54 {
55     byte b1;
56     expect(_tomlifyValue(b1)).toEqual(`0`);
57 
58     byte b2 = byte.max;
59     expect(_tomlifyValue(b2)).toEqual(`127`);
60 
61     byte b3 = byte.min;
62     expect(_tomlifyValue(b3)).toEqual(`-128`);
63 }
64 
65 @("Encode `ubyte` fields")
66 unittest
67 {
68     ubyte ub1;
69     expect(_tomlifyValue(ub1)).toEqual(`0`);
70 
71     ubyte ub2 = 127;
72     expect(_tomlifyValue(ub2)).toEqual(`127`);
73 
74     ubyte ub3 = ubyte.max;
75     expect(_tomlifyValue(ub3)).toEqual(`255`);
76 }
77 
78 @("Encode `short` fields")
79 unittest
80 {
81     short s1;
82     expect(_tomlifyValue(s1)).toEqual(`0`);
83 
84     short s2 = short.max;
85     expect(_tomlifyValue(s2)).toEqual(`32_767`);
86 
87     short s3 = short.min;
88     expect(_tomlifyValue(s3)).toEqual(`-32_768`);
89 }
90 
91 @("Encode `ushort` fields")
92 unittest
93 {
94     ushort us1;
95     expect(_tomlifyValue(us1)).toEqual(`0`);
96 
97     ushort us2 = 32_768;
98     expect(_tomlifyValue(us2)).toEqual(`32_768`);
99 
100     ushort us3 = ushort.max;
101     expect(_tomlifyValue(us3)).toEqual(`65_535`);
102 }
103 
104 @("Encode `int` fields")
105 unittest
106 {
107     int i1;
108     expect(_tomlifyValue(i1)).toEqual(`0`);
109 
110     int i2 = int.min;
111     expect(_tomlifyValue(i2)).toEqual(`-2_147_483_648`);
112 
113     int i3 = int.max;
114     expect(_tomlifyValue(i3)).toEqual(`2_147_483_647`);
115 }
116 
117 @("Encode `uint` fields")
118 unittest
119 {
120     uint ui1 = uint(0);
121     expect(_tomlifyValue(ui1)).toEqual(`0`);
122 
123     uint ui2 = uint(2_147_483_648);
124     expect(_tomlifyValue(ui2)).toEqual(`2_147_483_648`);
125 
126     uint ui3 = uint(uint.max);
127     expect(_tomlifyValue(ui3)).toEqual(`4_294_967_295`);
128 }
129 
130 @("Encode `long` fields")
131 unittest
132 {
133     long l1;
134     expect(_tomlifyValue(l1)).toEqual(`0`);
135 
136     long l2 = long.min;
137     expect(_tomlifyValue(l2)).toEqual(`-9_223_372_036_854_775_808`);
138 
139     long l3 = long.max;
140     expect(_tomlifyValue(l3)).toEqual(`9_223_372_036_854_775_807`);
141 }
142 
143 @("Encode `ulong` fields")
144 unittest
145 {
146     ulong ul1;
147     expect(_tomlifyValue(ul1)).toEqual(`0`);
148 
149     ulong ul2 = long.max.to!ulong;
150     expect(_tomlifyValue(ul2)).toEqual(`9_223_372_036_854_775_807`);
151 
152     ulong ul3 = long.max.to!ulong + 1;
153     expect({ _tomlifyValue(ul3); }).toThrow!TomlEncodingException;
154 
155     ulong ul4 = ulong.max;
156     expect({ _tomlifyValue(ul4); }).toThrow!TomlEncodingException;
157 }
158 
159 @("Separators should not be added to 4-digit negative numbers")
160 unittest
161 {
162     int n = -1234;
163     expect(_tomlifyValue(n)).toEqual(`-1234`);
164 }