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 }