diff --git a/tokio-fs/src/file/mod.rs b/tokio-fs/src/file/mod.rs index 5d64db1a6..b2b2ceed4 100644 --- a/tokio-fs/src/file/mod.rs +++ b/tokio-fs/src/file/mod.rs @@ -6,11 +6,13 @@ mod create; mod metadata; mod open; mod open_options; +mod seek; pub use self::create::CreateFuture; pub use self::metadata::MetadataFuture; pub use self::open::OpenFuture; pub use self::open_options::OpenOptions; +pub use self::seek::SeekFuture; use tokio_io::{AsyncRead, AsyncWrite}; @@ -100,6 +102,16 @@ impl File { ::blocking_io(|| self.std().seek(pos)) } + /// Seek to an offset, in bytes, in a stream. + /// + /// Similar to `poll_seek`, but returning a `Future`. + /// + /// This method consumes the `File` and returns it back when the future + /// completes. + pub fn seek(self, pos: io::SeekFrom) -> SeekFuture { + SeekFuture::new(self, pos) + } + /// Attempts to sync all OS-internal metadata to disk. /// /// This function will attempt to ensure that all in-core data reaches the diff --git a/tokio-fs/src/file/seek.rs b/tokio-fs/src/file/seek.rs new file mode 100644 index 000000000..e3523870c --- /dev/null +++ b/tokio-fs/src/file/seek.rs @@ -0,0 +1,37 @@ +use super::File; + +use futures::{Future, Poll}; + +use std::io; + +/// Future returned by `File::seek` +#[derive(Debug)] +pub struct SeekFuture { + inner: Option, + pos: io::SeekFrom, +} + +impl SeekFuture { + pub(crate) fn new(file: File, pos: io::SeekFrom) -> Self { + Self { + pos, + inner: Some(file), + } + } +} + +impl Future for SeekFuture { + type Item = (File, u64); + type Error = io::Error; + + fn poll(&mut self) -> Poll { + let pos = try_ready!( + self.inner + .as_mut() + .expect("Cannot poll `SeekFuture` after it resolves") + .poll_seek(self.pos) + ); + let inner = self.inner.take().unwrap(); + Ok((inner, pos).into()) + } +} diff --git a/tokio-fs/tests/file.rs b/tokio-fs/tests/file.rs index b512e5f50..05e46d299 100644 --- a/tokio-fs/tests/file.rs +++ b/tokio-fs/tests/file.rs @@ -16,7 +16,7 @@ use rand::{thread_rng, Rng}; use tempdir::TempDir; use std::fs::File as StdFile; -use std::io::Read; +use std::io::{Read, SeekFrom}; #[test] fn read_write() { @@ -103,3 +103,39 @@ fn metadata() { rx.wait().unwrap(); } + +#[test] +fn seek() { + let dir = TempDir::new("tokio-fs-tests").unwrap(); + let file_path = dir.path().join("seek.txt"); + + let pool = Builder::new().pool_size(1).build(); + + let (tx, rx) = oneshot::channel(); + + pool.spawn( + OpenOptions::new() + .create(true) + .read(true) + .write(true) + .open(file_path) + .and_then(|file| io::write_all(file, "Hello, world!")) + .and_then(|(file, _)| file.seek(SeekFrom::End(-6))) + .and_then(|(file, _)| io::read_exact(file, vec![0; 5])) + .and_then(|(file, buf)| { + assert_eq!(buf, b"world"); + file.seek(SeekFrom::Start(0)) + }) + .and_then(|(file, _)| io::read_exact(file, vec![0; 5])) + .and_then(|(_, buf)| { + assert_eq!(buf, b"Hello"); + Ok(()) + }) + .then(|r| { + let _ = r.unwrap(); + tx.send(()) + }), + ); + + rx.wait().unwrap(); +}