positioned_io2/
slice.rs

1use std::cmp::min;
2use std::io;
3
4use super::{ReadAt, Size, WriteAt};
5
6/// A window into another `ReadAt` or `WriteAt`.
7///
8/// Given an existing positioned I/O, this presents a limited view of it.
9///
10/// # Examples
11///
12/// Some slices have size restrictions:
13///
14/// ```rust
15/// # use std::io;
16/// use positioned_io2::{ReadAt, Slice};
17///
18/// # fn foo() -> io::Result<()> {
19/// let a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
20/// let slice = Slice::new(&a[..], 4, Some(4));
21///
22/// let mut buf = [0; 4];
23/// let bytes = slice.read_at(2, &mut buf)?;
24/// assert_eq!(bytes, 2);
25/// assert_eq!(buf, [6, 7, 0, 0]);
26/// # Ok(())
27/// # }
28/// # fn main() { foo().unwrap(); }
29/// ```
30///
31/// Some slices do not:
32///
33/// ```rust
34/// # use std::io;
35/// use positioned_io2::{WriteAt, Slice};
36///
37/// # fn foo() -> io::Result<()> {
38/// let mut v = vec![0, 1, 2, 3, 4, 5];
39/// let buf = [9; 3];
40///
41/// {
42///     let mut slice = Slice::new(&mut v, 2, None);
43///     slice.write_all_at(3, &buf)?;
44/// }
45///
46/// // The write goes right past the end.
47/// assert_eq!(v, vec![0, 1, 2, 3, 4, 9, 9, 9]);
48/// # Ok(())
49/// # }
50/// # fn main() { foo().unwrap(); }
51/// ```
52#[derive(Debug, Clone)]
53pub struct Slice<I> {
54    io: I,
55    offset: u64,
56    size: Option<u64>,
57}
58
59impl<I> Slice<I> {
60    /// Create a new `Slice`.
61    ///
62    /// The slice will be a view of `size` bytes, starting at `offset` in `io`.
63    /// If you do not pass a size, the size won't be limited.
64    pub fn new(io: I, offset: u64, size: Option<u64>) -> Self {
65        Slice { io, offset, size }
66    }
67
68    /// Get the available bytes starting at some point.
69    fn avail(&self, pos: u64, bytes: usize) -> usize {
70        match self.size {
71            None => bytes,
72            Some(size) if pos >= size => 0,
73            Some(size) => min(bytes as u64, size - pos) as usize,
74        }
75    }
76}
77impl<I: Size> Slice<I> {
78    /// Create a new `Slice` that goes to the end of `io`.
79    ///
80    /// Note that you can create a larger slice by passing a larger size to
81    /// `new()`, but it won't do you any good for reading.
82    pub fn new_to_end(io: I, offset: u64) -> io::Result<Self> {
83        match io.size() {
84            Ok(Some(size)) => Ok(Self::new(io, offset, Some(size - offset))),
85            _ => Err(io::Error::new(
86                io::ErrorKind::InvalidData,
87                "unknown base size",
88            )),
89        }
90    }
91}
92
93impl<I: ReadAt> ReadAt for Slice<I> {
94    fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
95        let bytes = self.avail(pos, buf.len());
96        self.io.read_at(pos + self.offset, &mut buf[..bytes])
97    }
98}
99
100impl<I: WriteAt> WriteAt for Slice<I> {
101    fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
102        let bytes = self.avail(pos, buf.len());
103        self.io.write_at(pos + self.offset, &buf[..bytes])
104    }
105
106    fn flush(&mut self) -> io::Result<()> {
107        self.io.flush()
108    }
109}
110
111impl<I> Size for Slice<I> {
112    fn size(&self) -> io::Result<Option<u64>> {
113        Ok(self.size)
114    }
115}