ts_io/
cursor.rs

1#[derive(Clone, Debug)]
2/// A simple cursor over a slice.
3pub struct Cursor<'a, T: Copy + Default> {
4    index: usize,
5    collection: &'a [T],
6}
7
8impl<T: Copy + Default> core::fmt::Display for Cursor<'_, T> {
9    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
10        write!(f, "index {} of {}", self.index, self.collection.len())
11    }
12}
13
14impl<'a, T: Copy + Default> Cursor<'a, T> {
15    /// Pull some items from this source into the specified buffer, returning how many items were
16    /// read.
17    ///
18    /// If this function returns `0` then either:
19    /// 1. The `buffer` is of length zero.
20    /// 2. All items have been read from the source.
21    ///
22    /// # Panics
23    /// * If it attempts to read out of bounds, which should only happen if the implementation is
24    ///   incorrect.
25    pub fn read(&mut self, buffer: &mut [T]) -> usize {
26        let item_count = buffer.len().min(self.collection.len() - self.index);
27        if item_count == 0 {
28            return 0;
29        }
30        let data = self
31            .read_count(item_count)
32            .expect("read should never read out of bounds");
33        buffer
34            .get_mut(..item_count)
35            .expect("read should never read out of bounds")
36            .copy_from_slice(data);
37        item_count
38    }
39
40    /// Pull exactly `N` items from the source into an array.
41    pub fn read_array<const N: usize>(&mut self) -> Result<[T; N], OutOfBounds> {
42        let mut output = [T::default(); N];
43        let data = self.read_count(N)?;
44        output.copy_from_slice(data);
45        Ok(output)
46    }
47
48    /// Pull the next `count` items from the source.
49    pub fn read_count<N: Into<usize>>(&mut self, count: N) -> Result<&[T], OutOfBounds> {
50        let count = count.into();
51        let data = self
52            .collection
53            .get(self.index..self.index + count)
54            .ok_or_else(|| OutOfBounds::new(count))?;
55        self.index += count;
56
57        Ok(data)
58    }
59}
60
61impl std::io::Read for Cursor<'_, u8> {
62    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
63        Ok(self.read(buf))
64    }
65}
66
67/// A read would take the cursor out of bounds.
68#[derive(Clone, Copy, Debug)]
69#[non_exhaustive]
70pub struct OutOfBounds {
71    requested: usize,
72}
73impl OutOfBounds {
74    fn new(requested: usize) -> Self {
75        Self { requested }
76    }
77}
78impl core::fmt::Display for OutOfBounds {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        write!(
81            f,
82            "reading {} bytes would take the cursor out of bounds",
83            self.requested,
84        )
85    }
86}
87impl core::error::Error for OutOfBounds {}