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