gufo_common/
read.rs

1use std::io::{Cursor, Seek};
2use std::slice::SliceIndex;
3use std::sync::Arc;
4
5use crate::math::*;
6
7pub trait GetExt<T> {
8    fn e_get<I: SliceIndex<[T]>>(
9        &self,
10        index: I,
11    ) -> Result<&<I as SliceIndex<[T]>>::Output, ReadError>;
12
13    fn e_get_mut<I: SliceIndex<[T]>>(
14        &mut self,
15        index: I,
16    ) -> Result<&mut <I as SliceIndex<[T]>>::Output, ReadError>;
17}
18
19impl<T> GetExt<T> for [T] {
20    fn e_get<I: SliceIndex<[T]>>(
21        &self,
22        index: I,
23    ) -> Result<&<I as SliceIndex<[T]>>::Output, ReadError> {
24        self.get(index).ok_or(ReadError::InvalidIndex)
25    }
26
27    fn e_get_mut<I: SliceIndex<[T]>>(
28        &mut self,
29        index: I,
30    ) -> Result<&mut <I as SliceIndex<[T]>>::Output, ReadError> {
31        self.get_mut(index).ok_or(ReadError::InvalidIndex)
32    }
33}
34
35pub trait ReadExt: std::io::BufRead + std::io::Seek {
36    fn read_array<const T: usize>(&mut self) -> Result<[u8; T], ReadError> {
37        let buf = &mut [0; T];
38        self.read_exact(buf)?;
39        Ok(*buf)
40    }
41
42    fn read_byte(&mut self) -> Result<u8, ReadError> {
43        let buf = &mut [0; 1];
44        self.read_exact(buf)?;
45        Ok(buf[0])
46    }
47}
48
49impl<T: AsRef<[u8]>> ReadExt for Cursor<T> {}
50
51pub trait SliceExt<'a>: std::io::BufRead + std::io::Seek {
52    fn slice_until(&mut self, byte: u8) -> Result<&'a [u8], ReadError>;
53    fn slice_to_end(&mut self) -> Result<&'a [u8], ReadError>;
54}
55
56impl<'a> SliceExt<'a> for Cursor<&'a [u8]> {
57    /// Read until `byte` and return as slice
58    ///
59    /// ```
60    /// # use std::io::Cursor;
61    /// # use gufo_common::read::*;
62    /// let mut s = Cursor::new(b"abc\0defgh\0end".as_slice());
63    /// assert_eq!(s.slice_until(b'\0').unwrap(), b"abc");
64    /// assert_eq!(s.slice_until(b'\0').unwrap(), b"defgh");
65    /// assert_eq!(s.slice_until(b'\0').unwrap(), b"end");
66    /// ```
67    fn slice_until(&mut self, byte: u8) -> Result<&'a [u8], ReadError> {
68        let start = self.position().usize()?;
69        let len = self
70            .get_ref()
71            .iter()
72            .skip(start)
73            .take_while(|x| **x != byte)
74            .count();
75        let end = start.safe_add(len)?;
76
77        self.seek_relative(len.safe_add(1)?.i64()?)?;
78
79        Ok(self.get_ref().get(start..end).unwrap())
80    }
81
82    /// Read until end and return as slice
83    ///
84    /// ```
85    /// # use std::io::Cursor;
86    /// # use gufo_common::read::*;
87    /// let mut s = Cursor::new(b"abc\0end".as_slice());
88    /// assert_eq!(s.slice_until(b'\0').unwrap(), b"abc");
89    /// assert_eq!(s.slice_to_end().unwrap(), b"end");
90    /// ```
91    fn slice_to_end(&mut self) -> Result<&'a [u8], ReadError> {
92        let start = self.position().usize()?;
93        let end = self.get_ref().len();
94
95        self.seek(std::io::SeekFrom::Start(end.u64()?))?;
96
97        Ok(self.get_ref().get(start..end).unwrap())
98    }
99}
100
101#[derive(Debug, thiserror::Error, Clone)]
102pub enum ReadError {
103    #[error("Math: {0}")]
104    Math(#[from] MathError),
105    #[error("IO: {0}")]
106    Io(#[from] Arc<std::io::Error>),
107    #[error("Invalid index")]
108    InvalidIndex,
109}
110
111impl From<std::io::Error> for ReadError {
112    fn from(value: std::io::Error) -> Self {
113        Arc::new(value).into()
114    }
115}