urex_binary_io/
writer.rs

1use half::f16;
2use std::io::{Result, Seek, Write};
3
4use crate::Endian;
5
6pub trait BinaryWrite {
7    /// Writes a bool to the internal stream.  
8    fn write_bool(&mut self, value: bool) -> Result<()>;
9    /// Writes a char to the internal stream.
10    fn write_char(&mut self, value: char) -> Result<()>;
11
12    /// Writes a u8 to the internal stream.
13    fn write_u8(&mut self, value: u8) -> Result<()>;
14    /// Writes a u16 to the internal stream.
15    fn write_u16(&mut self, value: u16) -> Result<()>;
16    /// Writes a u32 to the internal stream.
17    fn write_u32(&mut self, value: u32) -> Result<()>;
18    /// Writes a u64 to the internal stream.
19    fn write_u64(&mut self, value: u64) -> Result<()>;
20
21    /// Writes a i8 to the internal stream.
22    fn write_i8(&mut self, value: i8) -> Result<()>;
23    /// Writes a i16 to the internal stream.
24    fn write_i16(&mut self, value: i16) -> Result<()>;
25    /// Writes a i32 to the internal stream.
26    fn write_i32(&mut self, value: i32) -> Result<()>;
27    /// Writes a i64 to the internal stream.
28    fn write_i64(&mut self, value: i64) -> Result<()>;
29
30    /// Writes a f16 to the internal stream.
31    fn write_f16(&mut self, value: f32) -> Result<()>;
32    /// Writes a f32 to the internal stream.
33    fn write_f32(&mut self, value: f32) -> Result<()>;
34    /// Writes a f64 to the internal stream.
35    fn write_f64(&mut self, value: f64) -> Result<()>;
36
37    /// Writes a str as c-string (null-terminated) to the internal stream.
38    fn write_cstr(&mut self, value: &str) -> Result<()>;
39    /// Writes a str to the internal stream. If `write_len` is `Some(true)`, the length of the string will be written before the string itself.
40    fn write_str(&mut self, value: &str, write_len: Option<bool>) -> Result<()>;
41    /// Writes a byte slice to the internal stream. If `write_len` is `Some(true)`, the length of the byte slice will be written before the byte slice itself.
42    fn write_bytes(&mut self, value: &[u8], write_len: Option<bool>) -> Result<()>;
43
44    /// Writes a bool array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
45    fn write_bool_array(&mut self, value: Vec<bool>, write_len: Option<bool>) -> Result<()>;
46    /// Writes a char array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
47    fn write_char_array(&mut self, value: Vec<char>, write_len: Option<bool>) -> Result<()>;
48    /// Writes a u8 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
49    fn write_u8_array(&mut self, value: Vec<u8>, write_len: Option<bool>) -> Result<()>;
50    /// Writes a u16 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
51    fn write_u16_array(&mut self, value: Vec<u16>, write_len: Option<bool>) -> Result<()>;
52    /// Writes a u32 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
53    fn write_u32_array(&mut self, value: Vec<u32>, write_len: Option<bool>) -> Result<()>;
54    /// Writes a u64 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
55    fn write_u64_array(&mut self, value: Vec<u64>, write_len: Option<bool>) -> Result<()>;
56    /// Writes a i8 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
57    fn write_i8_array(&mut self, value: Vec<i8>, write_len: Option<bool>) -> Result<()>;
58    /// Writes a i16 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
59    fn write_i16_array(&mut self, value: Vec<i16>, write_len: Option<bool>) -> Result<()>;
60    /// Writes a i32 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
61    fn write_i32_array(&mut self, value: Vec<i32>, write_len: Option<bool>) -> Result<()>;
62    /// Writes a i64 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
63    fn write_i64_array(&mut self, value: Vec<i64>, write_len: Option<bool>) -> Result<()>;
64    /// Writes a f16 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
65    fn write_f16_array(&mut self, value: Vec<f32>, write_len: Option<bool>) -> Result<()>;
66    /// Writes a f32 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
67    fn write_f32_array(&mut self, value: Vec<f32>, write_len: Option<bool>) -> Result<()>;
68    /// Writes a f64 array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
69    fn write_f64_array(&mut self, value: Vec<f64>, write_len: Option<bool>) -> Result<()>;
70    /// Writes a str array as c-strings (null-terminated) to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
71    fn write_cstr_array(&mut self, value: Vec<&str>, write_len: Option<bool>) -> Result<()>;
72    /// Writes a str array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
73    fn write_str_array(&mut self, value: Vec<&str>, write_len: Option<bool>) -> Result<()>;
74    /// Writes a byte slice array to the internal stream. If `write_len` is `Some(true)`, the length of the array will be written before the array itself.
75    fn write_bytes_array(&mut self, value: Vec<&[u8]>, write_len: Option<bool>) -> Result<()>;
76}
77
78pub trait BinaryWriteAlign: BinaryWrite + Seek {
79    /// Align the reader to the given alignment.
80    fn align(&mut self, alignment: usize) -> Result<()>;
81    fn align4(&mut self) -> Result<()> {
82        self.align(4)
83    }
84    fn align8(&mut self) -> Result<()> {
85        self.align(8)
86    }
87    fn align16(&mut self) -> Result<()> {
88        self.align(16)
89    }
90}
91
92macro_rules! build_write_array_fn {
93    ($name:ident, $func:ident, $type:ty) => {
94        fn $name(&mut self, value: Vec<$type>, write_len: Option<bool>) -> Result<()> {
95            if write_len.is_none() || write_len.unwrap() {
96                self.write_u32(value.len() as u32)?;
97            }
98            value.iter().for_each(|v| {
99                self.$func(*v).unwrap();
100            });
101            Ok(())
102        }
103    };
104}
105
106macro_rules! build_write_array_fn_arg {
107    ($name:ident, $func:ident, $type:ty) => {
108        fn $name(&mut self, value: Vec<$type>, write_len: Option<bool>) -> Result<()> {
109            if write_len.is_none() || write_len.unwrap() {
110                self.write_u32(value.len() as u32)?;
111            }
112            value.iter().for_each(|v| {
113                self.$func(v, Some(true)).unwrap();
114            });
115            Ok(())
116        }
117    };
118}
119
120macro_rules! write_fn_generic {
121    () => {
122        fn write_bool(&mut self, value: bool) -> Result<()> {
123            self.inner.write_all(&[value as u8])
124        }
125
126        fn write_char(&mut self, value: char) -> Result<()> {
127            self.inner.write_all(&[value as u8])
128        }
129
130        fn write_f16(&mut self, value: f32) -> Result<()> {
131            let value_f16 = f16::from_f32(value);
132            self.write_u16(value_f16.to_bits())
133        }
134
135        fn write_cstr(&mut self, value: &str) -> Result<()> {
136            self.inner.write_all(value.as_bytes())?;
137            self.inner.write_all(&[0u8])
138        }
139
140        fn write_str(&mut self, value: &str, write_len: Option<bool>) -> Result<()> {
141            if write_len.is_none() || write_len.unwrap() {
142                let str_len: u32 = value.len() as u32;
143                self.write_u32(str_len)?;
144            }
145            self.inner.write_all(value.as_bytes())
146        }
147
148        fn write_bytes(&mut self, value: &[u8], write_len: Option<bool>) -> Result<()> {
149            if write_len.is_none() || write_len.unwrap() {
150                let bytes_len: u32 = value.len() as u32;
151                self.write_u32(bytes_len)?;
152            }
153            self.inner.write_all(value)
154        }
155
156        build_write_array_fn!(write_bool_array, write_bool, bool);
157        build_write_array_fn!(write_char_array, write_char, char);
158        build_write_array_fn!(write_f16_array, write_f16, f32);
159        build_write_array_fn!(write_cstr_array, write_cstr, &str);
160        build_write_array_fn_arg!(write_str_array, write_str, &str);
161        build_write_array_fn_arg!(write_bytes_array, write_bytes, &[u8]);
162    };
163}
164
165macro_rules! build_write_fn_ve {
166    ($type:ty) => {
167        paste::item! {
168            fn [< write_ $type >] (&mut self, value: $type) -> Result<()> {
169                match self.endian {
170                    Endian::Little => self.inner.write_all(&value.to_le_bytes()),
171                    Endian::Big => self.inner.write_all(&value.to_be_bytes()),
172                }
173            }
174        }
175        paste::item! {
176            fn [< write_ $type _array >] (&mut self, value: Vec<$type>, write_len: Option<bool>) -> Result<()> {
177                if write_len.is_none() || write_len.unwrap() {
178                    let array_len: u32 = value.len() as u32;
179                    match self.endian {
180                        Endian::Little => self.inner.write_all(&array_len.to_le_bytes())?,
181                        Endian::Big => self.inner.write_all(&array_len.to_be_bytes())?,
182                    };
183                }
184                // TODO - optimize this
185                match self.endian {
186                    Endian::Little => {
187                        value.iter().for_each(|v| {
188                            self.inner.write_all(&v.to_le_bytes()).unwrap();
189                        });
190                    }
191                    Endian::Big => {
192                        value.iter().for_each(|v| {
193                            self.inner.write_all(&v.to_be_bytes()).unwrap();
194                        });
195                    }
196                }
197                Ok(())
198            }
199        }
200    };
201}
202
203pub struct BinaryWriterVE<W> {
204    inner: W,
205    endian: Endian,
206}
207
208impl<W: Write> BinaryWriterVE<W> {
209    pub fn new(inner: W, endian: Endian) -> Self {
210        Self { inner, endian }
211    }
212}
213
214impl<W: Write> BinaryWrite for BinaryWriterVE<W> {
215    write_fn_generic!();
216    build_write_fn_ve!(u8);
217    build_write_fn_ve!(u16);
218    build_write_fn_ve!(u32);
219    build_write_fn_ve!(u64);
220
221    build_write_fn_ve!(i8);
222    build_write_fn_ve!(i16);
223    build_write_fn_ve!(i32);
224    build_write_fn_ve!(i64);
225    build_write_fn_ve!(f32);
226    build_write_fn_ve!(f64);
227}
228
229macro_rules! build_write_fn_be {
230    ($type:ty) => {
231        paste::item! {
232            fn [< write_ $type >] (&mut self, value: $type) -> Result<()> {
233                self.inner.write_all(&value.to_be_bytes())
234            }
235        }
236        paste::item! {
237            fn [< write_ $type _array >] (&mut self, value: Vec<$type>, write_len: Option<bool>) -> Result<()> {
238                if write_len.is_none() || write_len.unwrap() {
239                    self.write_u32(value.len() as u32)?;
240                }
241                // TODO - optimize this
242                value.iter().for_each(|v| {
243                    self.inner.write_all(&v.to_be_bytes()).unwrap();
244                });
245                Ok(())
246            }
247        }
248    };
249}
250pub struct BinaryWriterBE<W> {
251    inner: W,
252}
253
254impl<W: Write> BinaryWriterBE<W> {
255    pub fn new(inner: W) -> Self {
256        Self { inner }
257    }
258}
259
260impl<W: Write> BinaryWrite for BinaryWriterBE<W> {
261    write_fn_generic!();
262    build_write_fn_be!(u8);
263    build_write_fn_be!(u16);
264    build_write_fn_be!(u32);
265    build_write_fn_be!(u64);
266
267    build_write_fn_be!(i8);
268    build_write_fn_be!(i16);
269    build_write_fn_be!(i32);
270    build_write_fn_be!(i64);
271    build_write_fn_be!(f32);
272    build_write_fn_be!(f64);
273}
274
275macro_rules! build_write_fn_le {
276    ($type:ty) => {
277        paste::item! {
278            fn [< write_ $type >] (&mut self, value: $type) -> Result<()> {
279                self.inner.write_all(&value.to_le_bytes())
280            }
281        }
282        paste::item! {
283            fn [< write_ $type _array >] (&mut self, value: Vec<$type>, write_len: Option<bool>) -> Result<()> {
284                if write_len.is_none() || write_len.unwrap() {
285                    self.write_u32(value.len() as u32)?;
286                }
287                // TODO - optimize this
288                value.iter().for_each(|v| {
289                    self.inner.write_all(&v.to_le_bytes()).unwrap();
290                });
291                Ok(())
292            }
293        }
294    };
295}
296
297pub struct BinaryWriterLE<W> {
298    inner: W,
299}
300
301impl<W: Write> BinaryWriterLE<W> {
302    pub fn new(inner: W) -> Self {
303        Self { inner }
304    }
305}
306
307impl<W: Write> BinaryWrite for BinaryWriterLE<W> {
308    write_fn_generic!();
309    build_write_fn_le!(u8);
310    build_write_fn_le!(u16);
311    build_write_fn_le!(u32);
312    build_write_fn_le!(u64);
313
314    build_write_fn_le!(i8);
315    build_write_fn_le!(i16);
316    build_write_fn_le!(i32);
317    build_write_fn_le!(i64);
318    build_write_fn_le!(f32);
319    build_write_fn_le!(f64);
320}
321
322macro_rules! build_align_fn {
323    ($struct_:ident) => {
324        impl<R: Seek> $struct_<R> {
325            pub fn align(&mut self, alignment: usize) -> Result<()> {
326                let pos = self.inner.seek(std::io::SeekFrom::Current(0))?;
327                let rem = pos % alignment as u64;
328                if rem != 0 {
329                    self.inner.seek(std::io::SeekFrom::Current(rem as i64))?;
330                }
331                Ok(())
332            }
333        }
334
335        impl<R: Seek> Seek for $struct_<R> {
336            fn seek(&mut self, pos: std::io::SeekFrom) -> Result<u64> {
337                self.inner.seek(pos)
338            }
339
340            fn stream_position(&mut self) -> Result<u64> {
341                self.inner.stream_position()
342            }
343        }
344    };
345}
346
347build_align_fn!(BinaryWriterLE);
348build_align_fn!(BinaryWriterBE);
349build_align_fn!(BinaryWriterVE);
350
351#[cfg(test)]
352mod tests {
353    use super::*;
354    fn write_unsigned(writer: &mut impl (BinaryWrite)) -> Result<()> {
355        writer.write_u8(0x1 as u8)?;
356        writer.write_u16(0x1234 as u16)?;
357        writer.write_u32(0x12345678 as u32)?;
358        writer.write_u64(0x1234567890123456 as u64)?;
359        Ok(())
360    }
361
362    fn write_signed(writer: &mut dyn BinaryWrite) -> Result<()> {
363        writer.write_i8(0x1 as i8)?;
364        writer.write_i16(-0x1234 as i16)?;
365        writer.write_i32(0x12345678 as i32)?;
366        writer.write_i64(-0x1234567890123456 as i64)?;
367        Ok(())
368    }
369
370    fn write_float(writer: &mut dyn BinaryWrite) -> Result<()> {
371        writer.write_f16(0.16)?;
372        writer.write_f32(-0.32)?;
373        writer.write_f64(0.64)?;
374        Ok(())
375    }
376
377    #[test]
378    pub fn test_binary_writer() {
379        let mut writer_vec = vec![];
380        let mut writer = BinaryWriterVE::new(&mut writer_vec, Endian::Little);
381        write_unsigned(&mut writer).unwrap();
382        assert_eq!(writer_vec, &b"\x014\x12xV4\x12V4\x12\x90xV4\x12"[..]);
383
384        let mut writer_vec = vec![];
385        let mut writer = BinaryWriterVE::new(&mut writer_vec, Endian::Little);
386        write_signed(&mut writer).unwrap();
387        assert_eq!(
388            writer_vec,
389            &b"\x01\xcc\xedxV4\x12\xaa\xcb\xedo\x87\xa9\xcb\xed"[..]
390        );
391
392        let mut writer_vec = vec![];
393        let mut writer = BinaryWriterVE::new(&mut writer_vec, Endian::Little);
394        write_float(&mut writer).unwrap();
395        assert_eq!(writer_vec, &b"\x1f1\n\xd7\xa3\xbe{\x14\xaeG\xe1z\xe4?"[..]);
396
397        let mut writer_vec = vec![];
398        let mut writer = BinaryWriterVE::new(&mut writer_vec, Endian::Big);
399        write_unsigned(&mut writer).unwrap();
400        assert_eq!(writer_vec, &b"\x01\x124\x124Vx\x124Vx\x90\x124V"[..]);
401
402        let mut writer_vec = vec![];
403        let mut writer = BinaryWriterVE::new(&mut writer_vec, Endian::Big);
404        write_signed(&mut writer).unwrap();
405        assert_eq!(
406            writer_vec,
407            &b"\x01\xed\xcc\x124Vx\xed\xcb\xa9\x87o\xed\xcb\xaa"[..]
408        );
409
410        let mut writer_vec = vec![];
411        let mut writer = BinaryWriterVE::new(&mut writer_vec, Endian::Big);
412        write_float(&mut writer).unwrap();
413        assert_eq!(writer_vec, &b"1\x1f\xbe\xa3\xd7\n?\xe4z\xe1G\xae\x14{"[..]);
414    }
415
416    #[test]
417    pub fn test_binary_writer_le() {
418        let mut writer_vec = vec![];
419        let mut writer = BinaryWriterLE::new(&mut writer_vec);
420        write_unsigned(&mut writer).unwrap();
421        assert_eq!(writer_vec, &b"\x014\x12xV4\x12V4\x12\x90xV4\x12"[..]);
422
423        let mut writer_vec = vec![];
424        let mut writer = BinaryWriterLE::new(&mut writer_vec);
425        write_signed(&mut writer).unwrap();
426        assert_eq!(
427            writer_vec,
428            &b"\x01\xcc\xedxV4\x12\xaa\xcb\xedo\x87\xa9\xcb\xed"[..]
429        );
430
431        let mut writer_vec = vec![];
432        let mut writer = BinaryWriterLE::new(&mut writer_vec);
433        write_float(&mut writer).unwrap();
434        assert_eq!(writer_vec, &b"\x1f1\n\xd7\xa3\xbe{\x14\xaeG\xe1z\xe4?"[..]);
435    }
436
437    #[test]
438    pub fn test_binary_writer_be() {
439        let mut writer_vec = vec![];
440        let mut writer = BinaryWriterBE::new(&mut writer_vec);
441        write_unsigned(&mut writer).unwrap();
442        assert_eq!(writer_vec, &b"\x01\x124\x124Vx\x124Vx\x90\x124V"[..]);
443
444        let mut writer_vec = vec![];
445        let mut writer = BinaryWriterBE::new(&mut writer_vec);
446        write_signed(&mut writer).unwrap();
447        assert_eq!(
448            writer_vec,
449            &b"\x01\xed\xcc\x124Vx\xed\xcb\xa9\x87o\xed\xcb\xaa"[..]
450        );
451
452        let mut writer_vec = vec![];
453        let mut writer = BinaryWriterBE::new(&mut writer_vec);
454        write_float(&mut writer).unwrap();
455        assert_eq!(writer_vec, &b"1\x1f\xbe\xa3\xd7\n?\xe4z\xe1G\xae\x14{"[..]);
456    }
457}