genie_support/
read.rs

1use byteorder::{ReadBytesExt, LE};
2use std::convert::{TryFrom, TryInto};
3use std::io::{self, Error, ErrorKind, Read, Result};
4
5/// Read a 2-byte integer that uses -1 as an "absent" value.
6///
7/// ## Example
8///
9/// ```rust
10/// use genie_support::read_opt_u16;
11///
12/// let mut minus_one = std::io::Cursor::new(vec![0xFF, 0xFF]);
13/// let mut zero = std::io::Cursor::new(vec![0x00, 0x00]);
14///
15/// assert_eq!(read_opt_u16::<u16, _>(&mut minus_one).unwrap(), None);
16/// assert_eq!(read_opt_u16(&mut zero).unwrap(), Some(0));
17/// ```
18#[inline]
19pub fn read_opt_u16<T, R>(mut input: R) -> Result<Option<T>>
20where
21    T: TryFrom<u16>,
22    T::Error: std::error::Error + Send + Sync + 'static,
23    R: Read,
24{
25    let opt = match input.read_u16::<LE>()? {
26        0xFFFF => None,
27        v => Some(
28            v.try_into()
29                .map_err(|e| Error::new(ErrorKind::InvalidData, e))?,
30        ),
31    };
32    Ok(opt)
33}
34
35/// Read a 4-byte integer that uses -1 as an "absent" value.
36///
37/// ## Example
38///
39/// ```rust
40/// use genie_support::read_opt_u32;
41///
42/// let mut minus_one = std::io::Cursor::new(vec![0xFF, 0xFF, 0xFF, 0xFF]);
43/// let mut one = std::io::Cursor::new(vec![0x01, 0x00, 0x00, 0x00]);
44///
45/// assert_eq!(read_opt_u32::<u32, _>(&mut minus_one).unwrap(), None);
46/// assert_eq!(read_opt_u32(&mut one).unwrap(), Some(1));
47/// ```
48#[inline]
49pub fn read_opt_u32<T, R>(mut input: R) -> Result<Option<T>>
50where
51    T: TryFrom<u32>,
52    T::Error: std::error::Error + Send + Sync + 'static,
53    R: Read,
54{
55    let opt = match input.read_u32::<LE>()? {
56        0xFFFF_FFFF => None,
57        // HD Edition uses -2 in some places.
58        0xFFFF_FFFE => None,
59        v => Some(
60            v.try_into()
61                .map_err(|e| Error::new(ErrorKind::InvalidData, e))?,
62        ),
63    };
64    Ok(opt)
65}
66
67/// Extension trait that adds a `skip()` method to `Read` instances.
68pub trait ReadSkipExt {
69    /// Read and discard a number of bytes.
70    fn skip(&mut self, dist: u64) -> Result<()>;
71}
72
73impl<T: Read> ReadSkipExt for T {
74    fn skip(&mut self, dist: u64) -> Result<()> {
75        io::copy(&mut self.by_ref().take(dist), &mut io::sink())?;
76        Ok(())
77    }
78}