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