wagyu_model/utilities/
bytes.rs

1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use std::io::{Read, Result as IoResult, Write};
3
4pub trait ToBytes {
5    /// Serializes `self` into `writer`.
6    fn write<W: Write>(&self, writer: W) -> IoResult<()>;
7}
8
9pub trait FromBytes: Sized {
10    /// Reads `Self` from `reader`.
11    fn read<R: Read>(reader: R) -> IoResult<Self>;
12}
13
14macro_rules! array_bytes {
15    ($N:expr) => {
16        impl ToBytes for [u8; $N] {
17            #[inline]
18            fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
19                writer.write_all(self)
20            }
21        }
22
23        impl FromBytes for [u8; $N] {
24            #[inline]
25            fn read<R: Read>(mut reader: R) -> IoResult<Self> {
26                let mut arr = [0u8; $N];
27                reader.read_exact(&mut arr)?;
28                Ok(arr)
29            }
30        }
31
32        impl ToBytes for [u16; $N] {
33            #[inline]
34            fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
35                for num in self {
36                    writer.write_u16::<LittleEndian>(*num)?;
37                }
38                Ok(())
39            }
40        }
41
42        impl FromBytes for [u16; $N] {
43            #[inline]
44            fn read<R: Read>(mut reader: R) -> IoResult<Self> {
45                let mut res = [0u16; $N];
46                reader.read_u16_into::<LittleEndian>(&mut res)?;
47                Ok(res)
48            }
49        }
50
51        impl ToBytes for [u32; $N] {
52            #[inline]
53            fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
54                for num in self {
55                    writer.write_u32::<LittleEndian>(*num)?;
56                }
57                Ok(())
58            }
59        }
60
61        impl FromBytes for [u32; $N] {
62            #[inline]
63            fn read<R: Read>(mut reader: R) -> IoResult<Self> {
64                let mut res = [0u32; $N];
65                reader.read_u32_into::<LittleEndian>(&mut res)?;
66                Ok(res)
67            }
68        }
69
70        impl ToBytes for [u64; $N] {
71            #[inline]
72            fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
73                for num in self {
74                    writer.write_u64::<LittleEndian>(*num)?;
75                }
76                Ok(())
77            }
78        }
79
80        impl FromBytes for [u64; $N] {
81            #[inline]
82            fn read<R: Read>(mut reader: R) -> IoResult<Self> {
83                let mut res = [0u64; $N];
84                reader.read_u64_into::<LittleEndian>(&mut res)?;
85                Ok(res)
86            }
87        }
88    };
89}
90
91array_bytes!(0);
92array_bytes!(1);
93array_bytes!(2);
94array_bytes!(3);
95array_bytes!(4);
96array_bytes!(5);
97array_bytes!(6);
98array_bytes!(7);
99array_bytes!(8);
100array_bytes!(9);
101array_bytes!(10);
102array_bytes!(11);
103array_bytes!(12);
104array_bytes!(13);
105array_bytes!(14);
106array_bytes!(15);
107array_bytes!(16);
108array_bytes!(17);
109array_bytes!(18);
110array_bytes!(19);
111array_bytes!(20);
112array_bytes!(21);
113array_bytes!(22);
114array_bytes!(23);
115array_bytes!(24);
116array_bytes!(25);
117array_bytes!(26);
118array_bytes!(27);
119array_bytes!(28);
120array_bytes!(29);
121array_bytes!(30);
122array_bytes!(31);
123array_bytes!(32);
124
125/// Takes as input a sequence of structs, and converts them to a series of
126/// bytes. All traits that implement `Bytes` can be automatically converted to
127/// bytes in this manner.
128#[macro_export]
129macro_rules! to_bytes {
130    ($($x:expr),*) => ({
131        use std::io::Cursor;
132        let mut buf = Cursor::new(vec![]);
133        {$crate::push_to_vec!(buf, $($x),*)}.map(|_| buf.into_inner())
134    });
135}
136
137#[macro_export]
138macro_rules! push_to_vec {
139    ($buf:expr, $y:expr, $($x:expr),*) => ({
140        {
141            ToBytes::write(&$y, &mut $buf)
142        }.and({$crate::push_to_vec!($buf, $($x),*)})
143    });
144
145    ($buf:expr, $x:expr) => ({
146        ToBytes::write(&$x, &mut $buf)
147    })
148}
149
150impl ToBytes for u8 {
151    #[inline]
152    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
153        writer.write_u8(*self)
154    }
155}
156
157impl FromBytes for u8 {
158    #[inline]
159    fn read<R: Read>(mut reader: R) -> IoResult<Self> {
160        reader.read_u8()
161    }
162}
163
164impl ToBytes for u16 {
165    #[inline]
166    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
167        writer.write_u16::<LittleEndian>(*self)
168    }
169}
170
171impl FromBytes for u16 {
172    #[inline]
173    fn read<R: Read>(mut reader: R) -> IoResult<Self> {
174        reader.read_u16::<LittleEndian>()
175    }
176}
177
178impl ToBytes for u32 {
179    #[inline]
180    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
181        writer.write_u32::<LittleEndian>(*self)
182    }
183}
184
185impl FromBytes for u32 {
186    #[inline]
187    fn read<R: Read>(mut reader: R) -> IoResult<Self> {
188        reader.read_u32::<LittleEndian>()
189    }
190}
191
192impl ToBytes for u64 {
193    #[inline]
194    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
195        writer.write_u64::<LittleEndian>(*self)
196    }
197}
198
199impl FromBytes for u64 {
200    #[inline]
201    fn read<R: Read>(mut reader: R) -> IoResult<Self> {
202        reader.read_u64::<LittleEndian>()
203    }
204}
205
206impl ToBytes for () {
207    #[inline]
208    fn write<W: Write>(&self, _writer: W) -> IoResult<()> {
209        Ok(())
210    }
211}
212
213impl FromBytes for () {
214    #[inline]
215    fn read<R: Read>(_bytes: R) -> IoResult<Self> {
216        Ok(())
217    }
218}
219
220impl ToBytes for bool {
221    #[inline]
222    fn write<W: Write>(&self, writer: W) -> IoResult<()> {
223        u8::write(&(*self as u8), writer)
224    }
225}
226
227impl FromBytes for bool {
228    #[inline]
229    fn read<R: Read>(reader: R) -> IoResult<Self> {
230        match u8::read(reader) {
231            Ok(0) => Ok(false),
232            Ok(1) => Ok(true),
233            Ok(_) => Err(::std::io::ErrorKind::Other.into()),
234            Err(err) => Err(err),
235        }
236    }
237}
238
239impl<T: ToBytes> ToBytes for [T] {
240    #[inline]
241    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
242        for item in self {
243            item.write(&mut writer)?;
244        }
245        Ok(())
246    }
247}
248
249impl<T: ToBytes> ToBytes for Vec<T> {
250    #[inline]
251    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
252        for item in self {
253            item.write(&mut writer)?;
254        }
255        Ok(())
256    }
257}
258
259impl<'a, T: 'a + ToBytes> ToBytes for &'a [T] {
260    #[inline]
261    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
262        for item in *self {
263            item.write(&mut writer)?;
264        }
265        Ok(())
266    }
267}
268
269impl<'a, T: 'a + ToBytes> ToBytes for &'a T {
270    #[inline]
271    fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
272        (*self).write(&mut writer)
273    }
274}
275
276impl FromBytes for Vec<u8> {
277    #[inline]
278    fn read<R: Read>(mut reader: R) -> IoResult<Self> {
279        let mut buf = Vec::new();
280        let _ = reader.read_to_end(&mut buf)?;
281        Ok(buf)
282    }
283}
284
285#[cfg(test)]
286mod test {
287    use super::ToBytes;
288    #[test]
289    fn test_macro_empty() {
290        let array: Vec<u8> = vec![];
291        let bytes: Vec<u8> = to_bytes![array].unwrap();
292        assert_eq!(&bytes, &array);
293        assert_eq!(bytes.len(), 0);
294    }
295
296    #[test]
297    fn test_macro() {
298        let array1 = [1u8; 32];
299        let array2 = [2u8; 16];
300        let array3 = [3u8; 8];
301        let bytes = to_bytes![array1, array2, array3].unwrap();
302        assert_eq!(bytes.len(), 56);
303
304        let mut actual_bytes = Vec::new();
305        actual_bytes.extend_from_slice(&array1);
306        actual_bytes.extend_from_slice(&array2);
307        actual_bytes.extend_from_slice(&array3);
308        assert_eq!(bytes, actual_bytes);
309    }
310}