positioned_io_preview/
cursor.rs

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