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}