positioned_io/lib.rs
1//! This crate allows you to specify an offset for reads and writes,
2//! without changing the current position in a file. This is similar to
3//! [`pread()` and `pwrite()`][pread] in C.
4//!
5//! The major advantages of this type of I/O are:
6//!
7//! * You don't need to seek before doing a random-access read or write, which is convenient.
8//! * Reads don't modify the file at all, so don't require mutability.
9//!
10//! [pread]: http://man7.org/linux/man-pages/man2/pread.2.html
11//!
12//! # Examples
13//!
14//! Read the fifth 512-byte sector of a file:
15//!
16//! ```
17//! # use std::error::Error;
18//! #
19//! # fn try_main() -> Result<(), Box<dyn Error>> {
20//! use std::fs::File;
21//! use positioned_io::ReadAt;
22//!
23//! // note that file does not need to be mut
24//! let file = File::open("tests/pi.txt")?;
25//!
26//! // read up to 512 bytes
27//! let mut buf = [0; 512];
28//! let bytes_read = file.read_at(2048, &mut buf)?;
29//! # assert!(buf.starts_with(b"4"));
30//! # Ok(())
31//! # }
32//! #
33//! # fn main() {
34//! # try_main().unwrap();
35//! # }
36//! ```
37//!
38//! **Note:** If possible use the
39//! [`RandomAccessFile`](struct.RandomAccessFile.html) wrapper. `ReadAt`
40//! directly on `File` is very slow on Windows.
41//!
42//! Write an integer to the middle of a file:
43//!
44//! ```no_run
45//! # #[cfg(feature = "byteorder")]
46//! # extern crate byteorder;
47//! # use std::io;
48//! #
49//! # fn try_main() -> io::Result<()> {
50//! # #[cfg(feature = "byteorder")]
51//! # {
52//! use std::fs::OpenOptions;
53//! use positioned_io::WriteAt;
54//! use byteorder::{ByteOrder, LittleEndian};
55//!
56//! // put the integer in a buffer
57//! let mut buf = [0; 4];
58//! LittleEndian::write_u32(&mut buf, 1234);
59//!
60//! // write it to the file
61//! let mut file = OpenOptions::new().write(true).open("foo.data")?;
62//! file.write_all_at(1 << 20, &buf)?;
63//! # }
64//! # Ok(())
65//! # }
66//! # fn main() {
67//! # try_main().unwrap()
68//! # }
69//! ```
70//!
71//! Or, more simply:
72//!
73//! ```no_run
74//! # #[cfg(feature = "byteorder")]
75//! # extern crate byteorder;
76//! # use std::io;
77//! #
78//! # fn try_main() -> io::Result<()> {
79//! # #[cfg(feature = "byteorder")]
80//! # {
81//! use std::fs::OpenOptions;
82//! use byteorder::LittleEndian;
83//! use positioned_io::WriteBytesAtExt;
84//!
85//! let mut file = OpenOptions::new().write(true).open("foo.data")?;
86//! file.write_u32_at::<LittleEndian>(1 << 20, 1234)?;
87//! # }
88//! # Ok(())
89//! # }
90//! # fn main() {
91//! # try_main().unwrap()
92//! # }
93//! ```
94//!
95//! Read from anything else that supports `ReadAt`, like a byte array:
96//!
97//! ```rust
98//! # #[cfg(feature = "byteorder")]
99//! # extern crate byteorder;
100//! # use std::io;
101//! #
102//! # fn try_main() -> io::Result<()> {
103//! # #[cfg(feature = "byteorder")]
104//! {
105//! use byteorder::BigEndian;
106//! use positioned_io::ReadBytesAtExt;
107//!
108//! let buf = [0, 5, 254, 212, 0, 3];
109//! let n = buf.as_ref().read_i16_at::<BigEndian>(2)?;
110//! assert_eq!(n, -300);
111//! # }
112//! # Ok(())
113//! # }
114//! # fn main() {
115//! # try_main().unwrap()
116//! # }
117//! ```
118
119#![doc(html_root_url = "https://docs.rs/positioned-io/0.3.4")]
120#![warn(missing_debug_implementations)]
121#![warn(bare_trait_objects)]
122
123#[cfg(feature = "byteorder")]
124extern crate byteorder;
125#[cfg(unix)]
126extern crate libc;
127
128mod cursor;
129pub use crate::cursor::{Cursor, SizeCursor};
130
131mod slice;
132pub use crate::slice::Slice;
133
134#[cfg(feature = "byteorder")]
135mod byteio;
136use std::{fs::File, io};
137
138#[cfg(feature = "byteorder")]
139pub use crate::byteio::{ByteIo, ReadBytesAtExt, WriteBytesAtExt};
140
141/// Trait for reading bytes at an offset.
142///
143/// Implementations should be able to read bytes without changing any sort of
144/// read position. Self should not change at all. Buffering reads is unlikely
145/// to be useful, since each time `read_at()` is called, the position may be
146/// completely different.
147///
148/// # Examples
149///
150/// Read the fifth 512-byte sector of a file:
151///
152/// ```
153/// # use std::error::Error;
154/// #
155/// # fn try_main() -> Result<(), Box<dyn Error>> {
156/// use std::fs::File;
157/// use positioned_io::ReadAt;
158///
159/// // note that file does not need to be mut
160/// let file = File::open("tests/pi.txt")?;
161///
162/// // read up to 512 bytes
163/// let mut buf = [0; 512];
164/// let bytes_read = file.read_at(2048, &mut buf)?;
165/// # assert!(buf.starts_with(b"4"));
166/// # Ok(())
167/// # }
168/// #
169/// # fn main() {
170/// # try_main().unwrap();
171/// # }
172/// ```
173pub trait ReadAt {
174 /// Reads bytes from an offset in this source into a buffer, returning how
175 /// many bytes were read.
176 ///
177 /// This function may yield fewer bytes than the size of `buf`, if it was
178 /// interrupted or hit the "end of file".
179 ///
180 /// See [`Read::read()`](https://doc.rust-lang.org/std/io/trait.Read.html#tymethod.read)
181 /// for details.
182 fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize>;
183
184 /// Reads the exact number of bytes required to fill `buf` from an offset.
185 ///
186 /// Errors if the "end of file" is encountered before filling the buffer.
187 ///
188 /// See [`Read::read_exact()`](https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact)
189 /// for details.
190 fn read_exact_at(&self, mut pos: u64, mut buf: &mut [u8]) -> io::Result<()> {
191 while !buf.is_empty() {
192 match self.read_at(pos, buf) {
193 Ok(0) => break,
194 Ok(n) => {
195 let tmp = buf;
196 buf = &mut tmp[n..];
197 pos += n as u64;
198 }
199 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
200 Err(e) => return Err(e),
201 }
202 }
203 if !buf.is_empty() {
204 Err(io::Error::new(
205 io::ErrorKind::UnexpectedEof,
206 "failed to fill whole buffer",
207 ))
208 } else {
209 Ok(())
210 }
211 }
212}
213
214/// Trait for writing bytes at an offset.
215///
216/// Implementations should be able to write bytes at an offset, without
217/// changing any sort of write position. Self should not change at all.
218///
219/// When writing beyond the end of the underlying object it is extended and
220/// intermediate bytes are filled with the value 0.
221///
222/// # Examples
223///
224/// ```no_run
225/// # use std::error::Error;
226/// #
227/// # fn try_main() -> Result<(), Box<dyn Error>> {
228/// use std::fs::OpenOptions;
229/// use positioned_io::WriteAt;
230///
231/// let mut file = OpenOptions::new().write(true).open("tests/pi.txt")?;
232///
233/// // write some bytes
234/// let bytes_written = file.write_at(2, b"1415926535897932384626433")?;
235/// # Ok(())
236/// # }
237/// #
238/// # fn main() {
239/// # try_main().unwrap();
240/// # }
241/// ```
242pub trait WriteAt {
243 /// Writes bytes from a buffer to an offset, returning the number of bytes
244 /// written.
245 ///
246 /// This function may write fewer bytes than the size of `buf`, for example
247 /// if it is interrupted.
248 ///
249 /// See [`Write::write()`](https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.write)
250 /// for details.
251 fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize>;
252
253 /// Writes a complete buffer at an offset.
254 ///
255 /// Errors if it could not write the entire buffer.
256 ///
257 /// See [`Write::write_all()`](https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all)
258 /// for details.
259 fn write_all_at(&mut self, mut pos: u64, mut buf: &[u8]) -> io::Result<()> {
260 while !buf.is_empty() {
261 match self.write_at(pos, buf) {
262 Ok(0) => {
263 return Err(io::Error::new(
264 io::ErrorKind::WriteZero,
265 "failed to write whole buffer",
266 ))
267 }
268 Ok(n) => {
269 buf = &buf[n..];
270 pos += n as u64;
271 }
272 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
273 Err(e) => return Err(e),
274 }
275 }
276 Ok(())
277 }
278
279 /// Flush this writer, ensuring that any intermediately buffered data
280 /// reaches its destination.
281 ///
282 /// This should rarely do anything, since buffering is not very useful for
283 /// positioned writes.
284 ///
285 /// This should be equivalent to
286 /// [`Write::flush()`](https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush),
287 /// so it does not actually sync changes to disk when writing a `File`.
288 /// Use
289 /// [`File::sync_data()`](https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_data)
290 /// instead.
291 fn flush(&mut self) -> io::Result<()>;
292}
293
294/// Trait to get the size in bytes of an I/O object.
295///
296/// Implementing this for a types with `ReadAt` or `WriteAt` makes it easier
297/// for users to predict whether they will read past end-of-file. However, it
298/// may not be possible to implement for certain readers or writers that have
299/// unknown size.
300///
301/// # Examples
302///
303/// ```no_run
304/// # use std::error::Error;
305/// #
306/// # fn try_main() -> Result<(), Box<dyn Error>> {
307/// use std::fs::File;
308/// use positioned_io::Size;
309///
310/// let file = File::open("tests/pi.txt")?;
311/// let size = file.size()?;
312/// assert_eq!(size, Some(1000002));
313///
314/// // some special files do not have a known size
315/// let file = File::open("/dev/stdin")?;
316/// let size = file.size()?;
317/// assert_eq!(size, None);
318/// # Ok(())
319/// # }
320/// #
321/// # fn main() {
322/// # try_main().unwrap();
323/// # }
324/// ```
325pub trait Size {
326 /// Get the size of this object, in bytes.
327 ///
328 /// This function may return `Ok(None)` if the size is unknown, for example
329 /// for pipes.
330 fn size(&self) -> io::Result<Option<u64>>;
331}
332
333impl Size for File {
334 fn size(&self) -> io::Result<Option<u64>> {
335 let md = self.metadata()?;
336 if md.is_file() {
337 Ok(Some(md.len()))
338 } else {
339 Ok(None)
340 }
341 }
342}
343
344// Implementation for Unix files.
345#[cfg(unix)]
346mod unix;
347
348// Implementation for Windows files.
349#[cfg(windows)]
350mod windows;
351
352// RandomAccess file wrapper.
353mod raf;
354pub use crate::raf::RandomAccessFile;
355
356// Implementation for arrays, vectors.
357mod array;
358mod refs;
359mod vec;
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364
365 struct _AssertObjectSafe1(Box<dyn ReadAt>);
366 struct _AssertObjectSafe2(Box<dyn WriteAt>);
367 struct _AssertObjectSafe3(Box<dyn Size>);
368}