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