1 module reversineer.io; 2 3 import std.range; 4 5 import reversineer.structure; 6 7 /++ 8 + Reads a POD struct from a range of bytes. 9 + 10 + Params: 11 + T = type to read 12 + input = bytes to read data from 13 + val = destination to place read data at 14 +/ 15 T read(T, Range)(Range input) if (isPODStruct!T && isInputRange!Range && is(ElementType!Range : const ubyte)) { 16 T val = void; 17 read(input, val); 18 return val; 19 } 20 /// ditto 21 void read(T, Range)(Range input, ref T val) @safe if (isPODStruct!T && isInputRange!Range && is(ElementType!Range : const ubyte)) { 22 union Output { 23 T val; 24 ubyte[T.sizeof] bytes; 25 } 26 Output output = void; 27 static if (hasSlicing!Range) { 28 output.bytes = input[0..val.sizeof]; 29 } else { 30 foreach (ref target; output.bytes) { 31 target = input.front; 32 input.popFront(); 33 } 34 } 35 val = output.val; 36 } 37 /// ditto 38 void read(T, Range)(Range input, T* val) @safe if (isPODStruct!T && isInputRange!Range && is(ElementType!Range : const ubyte)) { 39 union Output { 40 T val; 41 ubyte[T.sizeof] bytes; 42 } 43 auto output = cast(Output*)val; 44 static if (hasSlicing!Range) { 45 output.bytes = input[0..T.sizeof]; 46 } else { 47 foreach (ref target; output.bytes) { 48 assert(!input.empty, "Not enough bytes left to read!"); 49 target = input.front; 50 input.popFront(); 51 } 52 } 53 } 54 /// Read struct from raw data 55 @safe unittest { 56 ubyte[] data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; 57 align(1) 58 struct X { 59 align(1): 60 ubyte a; 61 ushort b; 62 uint c; 63 ulong d; 64 ubyte[5] e; 65 } 66 67 auto readData = data.read!X(); 68 with (readData) { 69 assert(a == 0); 70 assert(b == 0x201); 71 assert(c == 0x6050403); 72 assert(d == 0x0E0D0C0B0A090807); 73 assert(e == [15, 16, 17, 18, 19]); 74 } 75 } 76 /// Read struct from raw data with destination premade 77 @safe unittest { 78 ubyte[] data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; 79 align(1) 80 struct X { 81 align(1): 82 ubyte a; 83 ushort b; 84 uint c; 85 ulong d; 86 ubyte[5] e; 87 } 88 89 X readData; 90 data.read!X(readData); 91 with (readData) { 92 assert(a == 0); 93 assert(b == 0x201); 94 assert(c == 0x6050403); 95 assert(d == 0x0E0D0C0B0A090807); 96 assert(e == [15, 16, 17, 18, 19]); 97 } 98 } 99 /// Read struct from raw data with destination preallocated on heap 100 @safe unittest { 101 ubyte[] data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; 102 align(1) 103 struct X { 104 align(1): 105 ubyte a; 106 ushort b; 107 uint c; 108 ulong d; 109 ubyte[5] e; 110 } 111 112 auto readData = new X; 113 data.read!X(readData); 114 with (readData) { 115 assert(a == 0); 116 assert(b == 0x201); 117 assert(c == 0x6050403); 118 assert(d == 0x0E0D0C0B0A090807); 119 assert(e == [15, 16, 17, 18, 19]); 120 } 121 }