positioned_io_preview/
slice.rs

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