1 module wasm_reader.leb;
2 
3 import std.range : ElementType, front, empty, popFront;
4 
5 version(unittest) {
6   import unit_threaded;
7 }
8 
9 struct varuint(T) {
10   static T decode(Range)(auto ref Range range) {
11     return range.decodeLEBunsigned!T;
12   }
13 }
14 struct varint(T) {
15   static T decode(Range)(auto ref Range range) {
16     return range.decodeLEBsigned!T;
17   }
18 }
19 
20 alias varuint1 = varuint!bool;
21 alias varuint7 = varuint!ubyte;
22 alias varuint32 = varuint!uint;
23 alias varint7 = varint!byte;
24 alias varint32 = varint!int;
25 alias varint64 = varint!long;
26 
27 T decodeLEBsigned(T, Range)(auto ref Range range) if (is(ElementType!(Range) == ubyte)) {
28   T result = 0;
29   size_t shift = 0;
30   enum size = T.sizeof * 8;
31   ubyte b = 0;
32   while(!range.empty) {
33     b = range.front();
34     range.popFront();
35     result |= ((b & 0x7f) << shift);
36     shift += 7;
37     if ((b & 0x80) == 0)
38       break;
39   }
40 
41   if ((shift < size) && (b & 0x40))
42     result |= (~0 << shift);
43   return result;
44 }
45 
46 unittest {
47   import std.stdio;
48   ubyte[] data = [0x9B,0xF1,0x59];
49   assert(data.decodeLEBsigned!int() == -624485);
50   assert(data.empty);
51 }
52 
53 T decodeLEBunsigned(T, Range)(auto ref Range range) if (is(ElementType!(Range) == ubyte)) {
54   T result = 0;
55   size_t shift = 0;
56   while(!range.empty) {
57     ubyte b = range.front();
58     range.popFront();
59     static if (T.sizeof < 2) {
60       result = cast(T)(b & 0x7f);
61     } else
62       result |= ((b & 0x7f) << shift);
63     if ((b & 0x80) == 0)
64       break;
65     shift += 7;
66   }
67   return result;
68 }
69 
70 unittest {
71   ubyte[] data = [0xe5,0x8e,0x26];
72   assert(data.decodeLEBunsigned!uint() == 624485);
73   assert(data.empty);
74 }
75 
76 unittest {
77   ubyte[] data = [0x00];
78   assert(data.decodeLEBunsigned!bool() == false);
79   assert(data.empty);
80 }
81 
82 unittest {
83   ubyte[] data = [0x01];
84   assert(data.decodeLEBunsigned!bool() == true);
85   assert(data.empty);
86 }