v2 / vlib / encoding / binary / stream.v
316 lines · 291 sloc · 7.88 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1module binary
2
3import io
4
5// ByteOrder decodes and encodes fixed-size integers using a specific byte order.
6pub interface ByteOrder {
7 u16(b []u8) u16
8 u32(b []u8) u32
9 u64(b []u8) u64
10 put_u16(mut b []u8, value u16)
11 put_u32(mut b []u8, value u32)
12 put_u64(mut b []u8, value u64)
13}
14
15// LittleEndian implements ByteOrder using little-endian encoding.
16pub struct LittleEndian {}
17
18// BigEndian implements ByteOrder using big-endian encoding.
19pub struct BigEndian {}
20
21pub const little_endian = LittleEndian{}
22pub const big_endian = BigEndian{}
23
24// u16 decodes a 16-bit unsigned integer from b using little-endian byte order.
25pub fn (_ LittleEndian) u16(b []u8) u16 {
26 return little_endian_u16(b)
27}
28
29// u32 decodes a 32-bit unsigned integer from b using little-endian byte order.
30pub fn (_ LittleEndian) u32(b []u8) u32 {
31 return little_endian_u32(b)
32}
33
34// u64 decodes a 64-bit unsigned integer from b using little-endian byte order.
35pub fn (_ LittleEndian) u64(b []u8) u64 {
36 return little_endian_u64(b)
37}
38
39// put_u16 encodes value into b using little-endian byte order.
40pub fn (_ LittleEndian) put_u16(mut b []u8, value u16) {
41 little_endian_put_u16(mut b, value)
42}
43
44// put_u32 encodes value into b using little-endian byte order.
45pub fn (_ LittleEndian) put_u32(mut b []u8, value u32) {
46 little_endian_put_u32(mut b, value)
47}
48
49// put_u64 encodes value into b using little-endian byte order.
50pub fn (_ LittleEndian) put_u64(mut b []u8, value u64) {
51 little_endian_put_u64(mut b, value)
52}
53
54// u16 decodes a 16-bit unsigned integer from b using big-endian byte order.
55pub fn (_ BigEndian) u16(b []u8) u16 {
56 return big_endian_u16(b)
57}
58
59// u32 decodes a 32-bit unsigned integer from b using big-endian byte order.
60pub fn (_ BigEndian) u32(b []u8) u32 {
61 return big_endian_u32(b)
62}
63
64// u64 decodes a 64-bit unsigned integer from b using big-endian byte order.
65pub fn (_ BigEndian) u64(b []u8) u64 {
66 return big_endian_u64(b)
67}
68
69// put_u16 encodes value into b using big-endian byte order.
70pub fn (_ BigEndian) put_u16(mut b []u8, value u16) {
71 big_endian_put_u16(mut b, value)
72}
73
74// put_u32 encodes value into b using big-endian byte order.
75pub fn (_ BigEndian) put_u32(mut b []u8, value u32) {
76 big_endian_put_u32(mut b, value)
77}
78
79// put_u64 encodes value into b using big-endian byte order.
80pub fn (_ BigEndian) put_u64(mut b []u8, value u64) {
81 big_endian_put_u64(mut b, value)
82}
83
84// read decodes fixed-size values from reader using order.
85pub fn read[T](mut reader io.Reader, order ByteOrder, mut data T) ! {
86 read_value(mut reader, order, mut data)!
87}
88
89// write encodes fixed-size values to writer using order.
90pub fn write[T](mut writer io.Writer, order ByteOrder, data T) ! {
91 write_value(mut writer, order, data)!
92}
93
94// size returns the number of bytes needed to encode data, or `-1` for unsupported types.
95pub fn size[T](data T) int {
96 return size_value(data)
97}
98
99fn size_value[T](data T) int {
100 $if T is bool || T is u8 || T is i8 {
101 return 1
102 } $else $if T is u16 || T is i16 {
103 return 2
104 } $else $if T is u32 || T is i32 || T is f32 {
105 return 4
106 } $else $if T is u64 || T is i64 || T is f64 {
107 return 8
108 } $else $if T is $array_fixed {
109 mut total := 0
110 for i in 0 .. data.len {
111 value_size := size_value(data[i])
112 if value_size < 0 {
113 return -1
114 }
115 total += value_size
116 }
117 return total
118 } $else $if T is $array {
119 mut total := 0
120 for value in data {
121 value_size := size(value)
122 if value_size < 0 {
123 return -1
124 }
125 total += value_size
126 }
127 return total
128 } $else $if T is $struct {
129 mut total := 0
130 $for field in T.fields {
131 if field.name == '_' {
132 return -1
133 }
134 field_size := size(data.$(field.name))
135 if field_size < 0 {
136 return -1
137 }
138 total += field_size
139 }
140 return total
141 } $else {
142 return -1
143 }
144}
145
146fn read_value[T](mut reader io.Reader, order ByteOrder, mut data T) ! {
147 $if T is bool {
148 mut buf := []u8{len: 1}
149 read_full(mut reader, mut buf)!
150 data = buf[0] != 0
151 } $else $if T is u8 {
152 mut buf := []u8{len: 1}
153 read_full(mut reader, mut buf)!
154 data = buf[0]
155 } $else $if T is i8 {
156 mut buf := []u8{len: 1}
157 read_full(mut reader, mut buf)!
158 data = i8(buf[0])
159 } $else $if T is u16 {
160 mut buf := []u8{len: 2}
161 read_full(mut reader, mut buf)!
162 data = order.u16(buf)
163 } $else $if T is i16 {
164 mut buf := []u8{len: 2}
165 read_full(mut reader, mut buf)!
166 data = i16(order.u16(buf))
167 } $else $if T is u32 {
168 mut buf := []u8{len: 4}
169 read_full(mut reader, mut buf)!
170 data = order.u32(buf)
171 } $else $if T is i32 {
172 mut buf := []u8{len: 4}
173 read_full(mut reader, mut buf)!
174 data = i32(order.u32(buf))
175 } $else $if T is u64 {
176 mut buf := []u8{len: 8}
177 read_full(mut reader, mut buf)!
178 data = order.u64(buf)
179 } $else $if T is i64 {
180 mut buf := []u8{len: 8}
181 read_full(mut reader, mut buf)!
182 data = i64(order.u64(buf))
183 } $else $if T is f32 {
184 mut buf := []u8{len: 4}
185 read_full(mut reader, mut buf)!
186 data = unsafe {
187 U32_F32{
188 u: order.u32(buf)
189 }.f
190 }
191 } $else $if T is f64 {
192 mut buf := []u8{len: 8}
193 read_full(mut reader, mut buf)!
194 data = unsafe {
195 U64_F64{
196 u: order.u64(buf)
197 }.f
198 }
199 } $else $if T is $array_fixed {
200 for i in 0 .. data.len {
201 read_value(mut reader, order, mut data[i])!
202 }
203 } $else $if T is $array {
204 $if T is []u8 {
205 read_full(mut reader, mut data)!
206 } $else {
207 for i in 0 .. data.len {
208 read_value(mut reader, order, mut data[i])!
209 }
210 }
211 } $else $if T is $struct {
212 $for field in T.fields {
213 if field.name == '_' {
214 return error('binary.read: structs with `_` fields are not supported')
215 }
216 read_value(mut reader, order, mut data.$(field.name))!
217 }
218 } $else {
219 return error('binary.read: unsupported type ${typeof(data).name}')
220 }
221}
222
223fn write_value[T](mut writer io.Writer, order ByteOrder, data T) ! {
224 $if T is bool {
225 write_full(mut writer, [u8(data)])!
226 } $else $if T is u8 {
227 write_full(mut writer, [u8(data)])!
228 } $else $if T is i8 {
229 write_full(mut writer, [u8(data)])!
230 } $else $if T is u16 {
231 mut buf := []u8{len: 2}
232 order.put_u16(mut buf, data)
233 write_full(mut writer, buf)!
234 } $else $if T is i16 {
235 mut buf := []u8{len: 2}
236 order.put_u16(mut buf, u16(data))
237 write_full(mut writer, buf)!
238 } $else $if T is u32 {
239 mut buf := []u8{len: 4}
240 order.put_u32(mut buf, data)
241 write_full(mut writer, buf)!
242 } $else $if T is i32 {
243 mut buf := []u8{len: 4}
244 order.put_u32(mut buf, u32(data))
245 write_full(mut writer, buf)!
246 } $else $if T is u64 {
247 mut buf := []u8{len: 8}
248 order.put_u64(mut buf, data)
249 write_full(mut writer, buf)!
250 } $else $if T is i64 {
251 mut buf := []u8{len: 8}
252 order.put_u64(mut buf, u64(data))
253 write_full(mut writer, buf)!
254 } $else $if T is f32 {
255 mut buf := []u8{len: 4}
256 bits := unsafe {
257 U32_F32{
258 f: data
259 }.u
260 }
261 order.put_u32(mut buf, bits)
262 write_full(mut writer, buf)!
263 } $else $if T is f64 {
264 mut buf := []u8{len: 8}
265 bits := unsafe {
266 U64_F64{
267 f: data
268 }.u
269 }
270 order.put_u64(mut buf, bits)
271 write_full(mut writer, buf)!
272 } $else $if T is $array_fixed {
273 for i in 0 .. data.len {
274 write_value(mut writer, order, data[i])!
275 }
276 } $else $if T is $array {
277 $if T is []u8 {
278 write_full(mut writer, data)!
279 } $else {
280 for value in data {
281 write_value(mut writer, order, value)!
282 }
283 }
284 } $else $if T is $struct {
285 $for field in T.fields {
286 if field.name == '_' {
287 return error('binary.write: structs with `_` fields are not supported')
288 }
289 write_value(mut writer, order, data.$(field.name))!
290 }
291 } $else {
292 return error('binary.write: unsupported type ${typeof(data).name}')
293 }
294}
295
296fn read_full(mut reader io.Reader, mut buf []u8) ! {
297 mut offset := 0
298 for offset < buf.len {
299 n := reader.read(mut buf[offset..])!
300 if n <= 0 || n > buf.len - offset {
301 return error('binary.read: reader returned an invalid number of bytes')
302 }
303 offset += n
304 }
305}
306
307fn write_full(mut writer io.Writer, buf []u8) ! {
308 mut offset := 0
309 for offset < buf.len {
310 n := writer.write(buf[offset..])!
311 if n <= 0 || n > buf.len - offset {
312 return error('binary.write: writer returned an invalid number of bytes')
313 }
314 offset += n
315 }
316}
317