positioned_io/
cursor.rs

1use std::{
2    io,
3    io::{Read, Seek, SeekFrom, Write},
4};
5
6use super::{ReadAt, Size, WriteAt};
7
8/// Adapts a `ReadAt` or `WriteAt` into a `Read` or `Write`.
9///
10/// This wraps anything that read and write at offsets, turning into an object
11/// that can read or write at a file position. This allows you to use those
12/// types with all the many functions that expect a `Read` or `Write`.
13///
14/// Note that seeking on `Cursor` has limited functionality. We don't know how
15/// many bytes are available, so we can't use `SeekFrom::End`.
16/// See [`SizeCursor`][SizeCursor] for another option.
17///
18/// [SizeCursor]: struct.SizeCursor.html
19///
20/// # Examples
21///
22/// ```no_run
23/// # use std::io::{self, Result, Read};
24/// # use std::fs::File;
25/// use positioned_io::{ReadAt, Cursor};
26///
27/// struct NetworkStorage {
28///     // A remote disk that supports random access.
29/// }
30/// # impl NetworkStorage {
31/// #   fn new(i: i32) -> Self { NetworkStorage { } }
32/// # }
33///
34/// impl ReadAt for NetworkStorage {
35///     // ...
36/// #   fn read_at(&self, pos: u64, buf: &mut [u8]) -> Result<usize> {
37/// #       Ok(0)
38/// #   }
39/// }
40///
41/// # const SOME_LOCATION: i32 = 1;
42/// # fn foo() -> Result<()> {
43/// // Adapt our storage into a Read.
44/// let storage = NetworkStorage::new(SOME_LOCATION);
45/// let curs = Cursor::new_pos(storage, 1 << 30);
46///
47/// // Copy a segment to a file.
48/// let mut input = curs.take(1 << 20);
49/// let mut output = File::create("segment.out")?;
50/// io::copy(&mut input, &mut output)?;
51/// # Ok(())
52/// # }
53/// ```
54#[derive(Debug, Clone)]
55pub struct Cursor<I> {
56    io: I,
57    pos: u64,
58}
59
60impl<I> Cursor<I> {
61    /// Create a new `Cursor` which starts reading at a specified offset.
62    ///
63    /// Pass in a `ReadAt` or `WriteAt` as `io`.
64    #[inline]
65    pub fn new_pos(io: I, pos: u64) -> Self {
66        Cursor { io, pos }
67    }
68
69    /// Create a new Cursor which starts reading at offset zero.
70    ///
71    /// Pass in a `ReadAt` or `WriteAt` as `io`.
72    #[inline]
73    pub fn new(io: I) -> Self {
74        Self::new_pos(io, 0)
75    }
76
77    /// Consume `self` and yield the inner `ReadAt` or `WriteAt`.
78    #[inline]
79    pub fn into_inner(self) -> I {
80        self.io
81    }
82
83    /// Borrow the inner `ReadAt` or `WriteAt`.
84    #[inline]
85    pub fn get_ref(&self) -> &I {
86        &self.io
87    }
88
89    /// Borrow the inner `ReadAt` or `WriteAt` mutably.
90    #[inline]
91    pub fn get_mut(&mut self) -> &mut I {
92        &mut self.io
93    }
94
95    /// Get the current read/write position.
96    #[inline]
97    pub fn position(&self) -> u64 {
98        self.pos
99    }
100
101    /// Set the current read/write position.
102    #[inline]
103    pub fn set_position(&mut self, pos: u64) {
104        self.pos = pos;
105    }
106}
107
108impl<I> Seek for Cursor<I> {
109    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
110        match pos {
111            SeekFrom::Start(p) => self.pos = p,
112            SeekFrom::Current(p) => {
113                let pos = self.pos as i64 + p;
114                if pos < 0 {
115                    return Err(io::Error::new(
116                        io::ErrorKind::InvalidInput,
117                        "seek to a negative position",
118                    ));
119                }
120                self.pos = pos as u64;
121            }
122            SeekFrom::End(_) => {
123                return Err(io::Error::new(
124                    io::ErrorKind::InvalidInput,
125                    "seek from unknown end",
126                ))
127            }
128        }
129        Ok(self.pos)
130    }
131}
132
133impl<I: ReadAt> Read for Cursor<I> {
134    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
135        let bytes = self.get_ref().read_at(self.pos, buf)?;
136        self.pos += bytes as u64;
137        Ok(bytes)
138    }
139}
140
141impl<I: WriteAt> Write for Cursor<I> {
142    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
143        let pos = self.pos;
144        let bytes = self.get_mut().write_at(pos, buf)?;
145        self.pos += bytes as u64;
146        Ok(bytes)
147    }
148
149    #[inline]
150    fn flush(&mut self) -> io::Result<()> {
151        WriteAt::flush(self.get_mut())
152    }
153}
154
155/// Adapts a `ReadAt` or `WriteAt` into a `Read` or `Write`, with better
156/// seeking.
157///
158/// This is just like [`Cursor`][Cursor], except that it requires an object
159/// that implements [`Size`][Size], and that it can seek from the end of the
160/// I/O object.
161///
162/// Eventually it will be legal to specialize `Cursor` for types that implement
163/// `Size`, see [RFC 1210][RFC].
164///
165/// [Cursor]: struct.Cursor.html
166/// [Size]: trait.Size.html
167/// [RFC]: https://github.com/rust-lang/rfcs/pull/1210
168#[derive(Debug, Clone)]
169pub struct SizeCursor<I: Size> {
170    cursor: Cursor<I>,
171}
172
173impl<I: Size> SizeCursor<I> {
174    /// Create a new `SizeCursor` which starts reading at a specified offset.
175    ///
176    /// Pass in a `ReadAt` or `WriteAt` as `io`.
177    #[inline]
178    pub fn new_pos(io: I, pos: u64) -> Self {
179        SizeCursor {
180            cursor: Cursor::new_pos(io, pos),
181        }
182    }
183
184    /// Create a new `SizeCursor` which starts reading at offset zero.
185    ///
186    /// Pass in a `ReadAt` or `WriteAt` as `io`.
187    #[inline]
188    pub fn new(io: I) -> Self {
189        SizeCursor {
190            cursor: Cursor::new(io),
191        }
192    }
193
194    #[inline]
195    pub fn as_cursor(&self) -> &Cursor<I> {
196        &self.cursor
197    }
198
199    #[inline]
200    pub fn as_cursor_mut(&mut self) -> &mut Cursor<I> {
201        &mut self.cursor
202    }
203
204    #[inline]
205    pub fn into_cursor(self) -> Cursor<I> {
206        self.cursor
207    }
208
209    #[inline]
210    pub fn into_inner(self) -> I {
211        self.cursor.io
212    }
213
214    #[inline]
215    pub fn get_ref(&self) -> &I {
216        &self.cursor.io
217    }
218
219    #[inline]
220    pub fn get_mut(&mut self) -> &mut I {
221        &mut self.cursor.io
222    }
223
224    #[inline]
225    pub fn position(&self) -> u64 {
226        self.cursor.position()
227    }
228
229    #[inline]
230    pub fn set_position(&mut self, pos: u64) {
231        self.cursor.set_position(pos)
232    }
233}
234
235impl<I: Size + ReadAt> Read for SizeCursor<I> {
236    #[inline]
237    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
238        self.cursor.read(buf)
239    }
240}
241
242impl<I: Size + WriteAt> Write for SizeCursor<I> {
243    #[inline]
244    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
245        self.cursor.write(buf)
246    }
247
248    #[inline]
249    fn flush(&mut self) -> io::Result<()> {
250        self.cursor.flush()
251    }
252}
253
254// We know how to seek from the end for SizeCursor.
255impl<I: Size> Seek for SizeCursor<I> {
256    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
257        let pos = match pos {
258            SeekFrom::Start(p) => p as i64,
259            SeekFrom::Current(p) => self.cursor.pos as i64 + p,
260            SeekFrom::End(p) => match self.get_ref().size() {
261                Err(e) => return Err(e),
262                Ok(None) => {
263                    return Err(io::Error::new(
264                        io::ErrorKind::InvalidData,
265                        "seek from unknown end",
266                    ))
267                }
268                Ok(Some(s)) => s as i64 + p,
269            },
270        };
271        self.cursor.pos = pos as u64;
272        Ok(self.cursor.pos)
273    }
274}