@@ -17,6 +17,7 @@ module geod24.bitblob;
17
17
18
18
static import std.ascii ;
19
19
import std.algorithm.iteration : each, map;
20
+ import std.algorithm.searching : countUntil, startsWith;
20
21
import std.format ;
21
22
import std.range ;
22
23
import std.utf ;
@@ -143,6 +144,41 @@ public struct BitBlob (size_t Size)
143
144
return buffer.idup;
144
145
}
145
146
147
+ /* **************************************************************************
148
+
149
+ Support deserialization
150
+
151
+ Vibe.d expects the `toString`/`fromString` to be present for it to
152
+ correctly serialize and deserialize a type.
153
+ This allows to use this type as parameter in `vibe.web.rest` methods,
154
+ or use it with Vibe.d's serialization module.
155
+ This function does more extensive validation of the input than the
156
+ constructor and can be given user input.
157
+
158
+ ***************************************************************************/
159
+
160
+ static auto fromString (scope const (char )[] str)
161
+ {
162
+ // Ignore prefix
163
+ if (str.startsWith(" 0x" ) || str.startsWith(" 0X" ))
164
+ str = str[2 .. $];
165
+
166
+ // Then check length
167
+ if (str.length != Size * 2 )
168
+ throw new Exception (
169
+ format(" Cannot parse string '%s' of length %s: Expected %s chars (%s with prefix)" ,
170
+ str, str.length, Size * 2 , Size * 2 + 2 ));
171
+
172
+ // Then content check
173
+ auto index = str.countUntil! (e => ! std.ascii.isAlphaNum (e));
174
+ if (index != - 1 )
175
+ throw new Exception (
176
+ format(" String '%s' has non alphanumeric character at index %s" ,
177
+ str, index));
178
+
179
+ return BitBlob (str);
180
+ }
181
+
146
182
pure nothrow @nogc :
147
183
148
184
/* **************************************************************************
@@ -214,22 +250,6 @@ public struct BitBlob (size_t Size)
214
250
this .data[idx++ ] = cast (ubyte )((chunk[0 ] << 4 ) + chunk[1 ]);
215
251
}
216
252
217
- /* **************************************************************************
218
-
219
- Support deserialization
220
-
221
- Vibe.d expects the `toString`/`fromString` to be present for it to
222
- correctly serialize and deserialize a type.
223
- This allows to use this type as parameter in `vibe.web.rest` methods,
224
- or use it with Vibe.d's serialization module.
225
-
226
- ***************************************************************************/
227
-
228
- static auto fromString (scope const (char )[] str)
229
- {
230
- return BitBlob! (Size)(str);
231
- }
232
-
233
253
// / Store the internal data
234
254
private ubyte [Size] data;
235
255
@@ -392,11 +412,28 @@ unittest
392
412
assert (collectException! AssertError (Hash(buff)) ! is null );
393
413
}
394
414
415
+ // Test that `fromString` throws Exceptions as and when expected
416
+ unittest
417
+ {
418
+ import std.exception ;
419
+ alias Hash = BitBlob! (32 );
420
+
421
+ // Error on the length
422
+ assert (collectException! Exception (Hash.fromString(" Hello world" )) ! is null );
423
+
424
+ char [GenesisBlockHashStr.length] buff = GenesisBlockHashStr;
425
+ Hash h = Hash(buff);
426
+ buff[5 ] = ' _' ;
427
+ // Error on the invalid char
428
+ assert (collectException! Exception (Hash.fromString(buff)) ! is null );
429
+ }
430
+
395
431
// Make sure the string parsing works at CTFE
396
432
unittest
397
433
{
398
434
static immutable BitBlob! 32 CTFEability = BitBlob! 32 (GenesisBlockHashStr);
399
435
static assert (CTFEability[] == GenesisBlockHash);
436
+ static assert (CTFEability == BitBlob! 32. fromString(GenesisBlockHashStr));
400
437
}
401
438
402
439
// Support for rvalue opCmp
0 commit comments