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 }