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 template sizeOf(var) if (is(var : varuint!T, T) || is(var : varint!T, T)) {
21   auto sizeOf(T)(T t) {
22     import core.bitop;
23     return bsr(t) / 7 + 1;
24   }
25 }
26 alias varuint1 = varuint!bool;
27 alias varuint7 = varuint!ubyte;
28 alias varuint32 = varuint!uint;
29 alias varint7 = varint!byte;
30 alias varint32 = varint!int;
31 alias varint64 = varint!long;
32 
33 T decodeLEBsigned(T, Range)(auto ref Range range) if (is(ElementType!(Range) == ubyte)) {
34   T result = 0;
35   size_t shift = 0;
36   enum size = T.sizeof * 8;
37   ubyte b = 0;
38   while(!range.empty) {
39     b = range.front();
40     range.popFront();
41     result |= ((b & 0x7f) << shift);
42     shift += 7;
43     if ((b & 0x80) == 0)
44       break;
45   }
46 
47   if ((shift < size) && (b & 0x40))
48     result |= (~0 << shift);
49   return result;
50 }
51 
52 unittest {
53   import std.stdio;
54   ubyte[] data = [0x9B,0xF1,0x59];
55   assert(data.decodeLEBsigned!int() == -624485);
56   assert(data.empty);
57 }
58 
59 T decodeLEBunsigned(T, Range)(auto ref Range range) if (is(ElementType!(Range) == ubyte)) {
60   T result = 0;
61   size_t shift = 0;
62   while(!range.empty) {
63     ubyte b = range.front();
64     range.popFront();
65     static if (T.sizeof < 2) {
66       result = cast(T)(b & 0x7f);
67     } else
68       result |= ((b & 0x7f) << shift);
69     if ((b & 0x80) == 0)
70       break;
71     shift += 7;
72   }
73   return result;
74 }
75 
76 unittest {
77   ubyte[] data = [0xe5,0x8e,0x26];
78   assert(data.decodeLEBunsigned!uint() == 624485);
79   assert(data.empty);
80 }
81 
82 unittest {
83   ubyte[] data = [0x00];
84   assert(data.decodeLEBunsigned!bool() == false);
85   assert(data.empty);
86 }
87 
88 unittest {
89   ubyte[] data = [0x01];
90   assert(data.decodeLEBunsigned!bool() == true);
91   assert(data.empty);
92 }