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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
use std::{cmp::min, io};
use super::{ReadAt, Size, WriteAt};
/// 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 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 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,
}
}
/// Consumes the slice, returning the underlying value.
pub fn into_inner(self) -> I {
self.io
}
/// Get a reference to the underlying value in this slice.
///
/// Note that IO on the returned value may escape the slice.
pub fn get_ref(&self) -> &I {
&self.io
}
/// Get a mutable reference to the underlying value in this slice.
///
/// Note that IO on the returned value may escape the slice.
pub fn get_mut(&mut self) -> &mut I {
&mut self.io
}
/// Get the offset that this slice starts at within the underlying IO.
pub fn offset(&self) -> u64 {
self.offset
}
/// Set the offset that this slice starts at within the underlying IO.
pub fn set_offset(&mut self, offset: u64) {
self.offset = offset
}
}
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)
}
}