fs: update to use std::future (#1269)

This commit is contained in:
andy finch
2019-07-11 09:05:49 -07:00
committed by Carl Lerche
parent 7ac8bfc821
commit 795e02f4c6
36 changed files with 492 additions and 305 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ members = [
"tokio-codec", "tokio-codec",
"tokio-current-thread", "tokio-current-thread",
"tokio-executor", "tokio-executor",
# "tokio-fs", "tokio-fs",
"tokio-futures", "tokio-futures",
"tokio-io", "tokio-io",
"tokio-macros", "tokio-macros",
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
cross: true cross: true
rust: $(nightly) rust: $(nightly)
crates: crates:
# - tokio-fs tokio-fs: []
tokio-reactor: [] tokio-reactor: []
tokio-signal: [] tokio-signal: []
tokio-tcp: tokio-tcp:
+5 -1
View File
@@ -24,9 +24,10 @@ categories = ["asynchronous", "network-programming", "filesystem"]
publish = false publish = false
[dependencies] [dependencies]
futures = "0.1.21" futures-core-preview = "0.3.0-alpha.17"
tokio-threadpool = { version = "0.2.0", path = "../tokio-threadpool" } tokio-threadpool = { version = "0.2.0", path = "../tokio-threadpool" }
tokio-io = { version = "0.2.0", path = "../tokio-io" } tokio-io = { version = "0.2.0", path = "../tokio-io" }
tokio-futures = { version = "0.2.0", path = "../tokio-futures" }
[dev-dependencies] [dev-dependencies]
rand = "0.6" rand = "0.6"
@@ -34,3 +35,6 @@ tempfile = "3"
tempdir = "0.3" tempdir = "0.3"
tokio-codec = { version = "0.2.0", path = "../tokio-codec" } tokio-codec = { version = "0.2.0", path = "../tokio-codec" }
tokio = { version = "0.2.0", path = "../tokio" } tokio = { version = "0.2.0", path = "../tokio" }
futures-channel-preview = "0.3.0-alpha.17"
futures-preview = { version = "0.3.0-alpha.17" }
futures-util-preview = "0.3.0-alpha.17"
@@ -1,15 +1,17 @@
//! Echo everything received on STDIN to STDOUT. //! Echo everything received on STDIN to STDOUT.
#![deny(deprecated, warnings)] #![deny(deprecated, warnings)]
#![feature(async_await)]
use tokio_codec::{FramedRead, FramedWrite, LinesCodec}; use tokio_codec::{FramedRead, FramedWrite, LinesCodec};
use tokio_fs::{stderr, stdin, stdout}; use tokio_fs::{stderr, stdin, stdout};
use tokio_threadpool::Builder; use tokio_threadpool::Builder;
use futures::{Future, Sink, Stream}; use futures_util::sink::SinkExt;
use std::io; use std::io;
pub fn main() -> Result<(), Box<dyn std::error::Error>> { #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = Builder::new().pool_size(1).build(); let pool = Builder::new().pool_size(1).build();
pool.spawn({ pool.spawn({
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Creates a new, empty directory at the provided path /// Creates a new, empty directory at the provided path
/// ///
@@ -34,10 +37,9 @@ impl<P> Future for CreateDirFuture<P>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::create_dir(&self.path)) crate::blocking_io(|| fs::create_dir(&self.path))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Recursively create a directory and all of its parent components if they /// Recursively create a directory and all of its parent components if they
/// are missing. /// are missing.
@@ -35,10 +38,9 @@ impl<P> Future for CreateDirAllFuture<P>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::create_dir_all(&self.path)) crate::blocking_io(|| fs::create_dir_all(&self.path))
} }
} }
+11 -7
View File
@@ -1,6 +1,9 @@
use super::File; use super::File;
use futures::{Future, Poll}; use std::future::Future;
use std::io; use std::io;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Future returned by `File::try_clone`. /// Future returned by `File::try_clone`.
/// ///
@@ -21,15 +24,16 @@ impl CloneFuture {
} }
impl Future for CloneFuture { impl Future for CloneFuture {
type Item = (File, File); type Output = Result<(File, File), (File, io::Error)>;
type Error = (File, io::Error);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
self.file let inner_self = Pin::get_mut(self);
inner_self
.file
.as_mut() .as_mut()
.expect("Cannot poll `CloneFuture` after it resolves") .expect("Cannot poll `CloneFuture` after it resolves")
.poll_try_clone() .poll_try_clone()
.map(|inner| inner.map(|cloned| (self.file.take().unwrap(), cloned))) .map(|inner| inner.map(|cloned| (inner_self.file.take().unwrap(), cloned)))
.map_err(|err| (self.file.take().unwrap(), err)) .map_err(|err| (inner_self.file.take().unwrap(), err))
} }
} }
+10 -8
View File
@@ -1,8 +1,11 @@
use super::File; use super::File;
use futures::{try_ready, Future, Poll};
use std::fs::File as StdFile; use std::fs::File as StdFile;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Future returned by `File::create` and resolves to a `File` instance. /// Future returned by `File::create` and resolves to a `File` instance.
#[derive(Debug)] #[derive(Debug)]
@@ -12,7 +15,7 @@ pub struct CreateFuture<P> {
impl<P> CreateFuture<P> impl<P> CreateFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
pub(crate) fn new(path: P) -> Self { pub(crate) fn new(path: P) -> Self {
CreateFuture { path } CreateFuture { path }
@@ -21,15 +24,14 @@ where
impl<P> Future for CreateFuture<P> impl<P> Future for CreateFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
type Item = File; type Output = io::Result<File>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
let std = try_ready!(crate::blocking_io(|| StdFile::create(&self.path))); let std = ready!(crate::blocking_io(|| StdFile::create(&self.path)))?;
let file = File::from_std(std); let file = File::from_std(std);
Ok(file.into()) Poll::Ready(Ok(file.into()))
} }
} }
+10 -7
View File
@@ -1,8 +1,11 @@
use super::File; use super::File;
use futures::{try_ready, Future, Poll};
use std::fs::File as StdFile; use std::fs::File as StdFile;
use std::fs::Metadata; use std::fs::Metadata;
use std::future::Future;
use std::io; use std::io;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
const POLL_AFTER_RESOLVE: &str = "Cannot poll MetadataFuture after it resolves"; const POLL_AFTER_RESOLVE: &str = "Cannot poll MetadataFuture after it resolves";
@@ -23,13 +26,13 @@ impl MetadataFuture {
} }
impl Future for MetadataFuture { impl Future for MetadataFuture {
type Item = (File, Metadata); type Output = io::Result<(File, Metadata)>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
let metadata = try_ready!(crate::blocking_io(|| StdFile::metadata(self.std()))); let inner = Pin::get_mut(self);
let metadata = ready!(crate::blocking_io(|| StdFile::metadata(inner.std())))?;
let file = self.file.take().expect(POLL_AFTER_RESOLVE); let file = inner.file.take().expect(POLL_AFTER_RESOLVE);
Ok((file, metadata).into()) Poll::Ready(Ok((file, metadata).into()))
} }
} }
+41 -17
View File
@@ -16,10 +16,12 @@ pub use self::open::OpenFuture;
pub use self::open_options::OpenOptions; pub use self::open_options::OpenOptions;
pub use self::seek::SeekFuture; pub use self::seek::SeekFuture;
use futures::Poll;
use std::fs::{File as StdFile, Metadata, Permissions}; use std::fs::{File as StdFile, Metadata, Permissions};
use std::io::{self, Read, Seek, Write}; use std::io::{self, Read, Seek, Write};
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
/// A reference to an open file on the filesystem. /// A reference to an open file on the filesystem.
@@ -103,7 +105,7 @@ impl File {
/// ``` /// ```
pub fn open<P>(path: P) -> OpenFuture<P> pub fn open<P>(path: P) -> OpenFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
OpenOptions::new().read(true).open(path) OpenOptions::new().read(true).open(path)
} }
@@ -142,7 +144,7 @@ impl File {
/// ``` /// ```
pub fn create<P>(path: P) -> CreateFuture<P> pub fn create<P>(path: P) -> CreateFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
CreateFuture::new(path) CreateFuture::new(path)
} }
@@ -191,7 +193,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error> { pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<io::Result<u64>> {
crate::blocking_io(|| self.std().seek(pos)) crate::blocking_io(|| self.std().seek(pos))
} }
@@ -243,7 +245,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_sync_all(&mut self) -> Poll<(), io::Error> { pub fn poll_sync_all(&mut self) -> Poll<io::Result<()>> {
crate::blocking_io(|| self.std().sync_all()) crate::blocking_io(|| self.std().sync_all())
} }
@@ -273,7 +275,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_sync_data(&mut self) -> Poll<(), io::Error> { pub fn poll_sync_data(&mut self) -> Poll<io::Result<()>> {
crate::blocking_io(|| self.std().sync_data()) crate::blocking_io(|| self.std().sync_data())
} }
@@ -305,7 +307,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_set_len(&mut self, size: u64) -> Poll<(), io::Error> { pub fn poll_set_len(&mut self, size: u64) -> Poll<io::Result<()>> {
crate::blocking_io(|| self.std().set_len(size)) crate::blocking_io(|| self.std().set_len(size))
} }
@@ -344,7 +346,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_metadata(&mut self) -> Poll<Metadata, io::Error> { pub fn poll_metadata(&mut self) -> Poll<io::Result<Metadata>> {
crate::blocking_io(|| self.std().metadata()) crate::blocking_io(|| self.std().metadata())
} }
@@ -366,7 +368,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_try_clone(&mut self) -> Poll<File, io::Error> { pub fn poll_try_clone(&mut self) -> Poll<io::Result<File>> {
crate::blocking_io(|| { crate::blocking_io(|| {
let std = self.std().try_clone()?; let std = self.std().try_clone()?;
Ok(File::from_std(std)) Ok(File::from_std(std))
@@ -437,7 +439,7 @@ impl File {
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error> { pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<io::Result<()>> {
crate::blocking_io(|| self.std().set_permissions(perm)) crate::blocking_io(|| self.std().set_permissions(perm))
} }
@@ -479,8 +481,15 @@ impl Read for File {
} }
impl AsyncRead for File { impl AsyncRead for File {
unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { fn poll_read(
false self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
match Pin::get_mut(self).read(buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
} }
} }
@@ -495,11 +504,26 @@ impl Write for File {
} }
impl AsyncWrite for File { impl AsyncWrite for File {
fn shutdown(&mut self) -> Poll<(), io::Error> { fn poll_write(
crate::blocking_io(|| { self: Pin<&mut Self>,
self.std = None; _cx: &mut Context<'_>,
Ok(()) buf: &[u8],
}) ) -> Poll<io::Result<usize>> {
match Pin::get_mut(self).write(buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self).flush() {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))
} }
} }
+11 -9
View File
@@ -1,19 +1,22 @@
use super::File; use super::File;
use futures::{try_ready, Future, Poll};
use std::fs::OpenOptions as StdOpenOptions; use std::fs::OpenOptions as StdOpenOptions;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Future returned by `File::open` and resolves to a `File` instance. /// Future returned by `File::open` and resolves to a `File` instance.
#[derive(Debug)] #[derive(Debug)]
pub struct OpenFuture<P> { pub struct OpenFuture<P: Unpin> {
options: StdOpenOptions, options: StdOpenOptions,
path: P, path: P,
} }
impl<P> OpenFuture<P> impl<P> OpenFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
pub(crate) fn new(options: StdOpenOptions, path: P) -> Self { pub(crate) fn new(options: StdOpenOptions, path: P) -> Self {
OpenFuture { options, path } OpenFuture { options, path }
@@ -22,15 +25,14 @@ where
impl<P> Future for OpenFuture<P> impl<P> Future for OpenFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
type Item = File; type Output = io::Result<File>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
let std = try_ready!(crate::blocking_io(|| self.options.open(&self.path))); let std = ready!(crate::blocking_io(|| self.options.open(&self.path)))?;
let file = File::from_std(std); let file = File::from_std(std);
Ok(file.into()) Poll::Ready(Ok(file.into()))
} }
} }
+1 -1
View File
@@ -90,7 +90,7 @@ impl OpenOptions {
/// [`open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open /// [`open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
pub fn open<P>(&self, path: P) -> OpenFuture<P> pub fn open<P>(&self, path: P) -> OpenFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
OpenFuture::new(self.0.clone(), path) OpenFuture::new(self.0.clone(), path)
} }
+11 -8
View File
@@ -1,6 +1,9 @@
use super::File; use super::File;
use futures::{try_ready, Future, Poll}; use std::future::Future;
use std::io; use std::io;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Future returned by `File::seek`. /// Future returned by `File::seek`.
#[derive(Debug)] #[derive(Debug)]
@@ -19,16 +22,16 @@ impl SeekFuture {
} }
impl Future for SeekFuture { impl Future for SeekFuture {
type Item = (File, u64); type Output = io::Result<(File, u64)>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
let pos = try_ready!(self let inner_self = Pin::get_mut(self);
let pos = ready!(inner_self
.inner .inner
.as_mut() .as_mut()
.expect("Cannot poll `SeekFuture` after it resolves") .expect("Cannot poll `SeekFuture` after it resolves")
.poll_seek(self.pos)); .poll_seek(inner_self.pos))?;
let inner = self.inner.take().unwrap(); let inner = inner_self.inner.take().unwrap();
Ok((inner, pos).into()) Poll::Ready(Ok((inner, pos).into()))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Creates a new hard link on the filesystem. /// Creates a new hard link on the filesystem.
/// ///
@@ -41,10 +44,9 @@ where
P: AsRef<Path>, P: AsRef<Path>,
Q: AsRef<Path>, Q: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::hard_link(&self.src, &self.dst)) crate::blocking_io(|| fs::hard_link(&self.src, &self.dst))
} }
} }
+13 -11
View File
@@ -30,6 +30,9 @@
//! [`AsyncRead`]: https://docs.rs/tokio-io/0.1/tokio_io/trait.AsyncRead.html //! [`AsyncRead`]: https://docs.rs/tokio-io/0.1/tokio_io/trait.AsyncRead.html
//! [tokio-threadpool]: https://docs.rs/tokio-threadpool/0.1/tokio_threadpool //! [tokio-threadpool]: https://docs.rs/tokio-threadpool/0.1/tokio_threadpool
#[macro_use]
extern crate tokio_futures;
mod create_dir; mod create_dir;
mod create_dir_all; mod create_dir_all;
pub mod file; pub mod file;
@@ -68,20 +71,19 @@ pub use crate::stdout::{stdout, Stdout};
pub use crate::symlink_metadata::{symlink_metadata, SymlinkMetadataFuture}; pub use crate::symlink_metadata::{symlink_metadata, SymlinkMetadataFuture};
pub use crate::write::{write, WriteFile}; pub use crate::write::{write, WriteFile};
use futures::Async::*;
use futures::Poll;
use std::io; use std::io;
use std::io::ErrorKind::{Other, WouldBlock}; use std::io::ErrorKind::{Other, WouldBlock};
use std::task::Poll;
use std::task::Poll::*;
fn blocking_io<F, T>(f: F) -> Poll<T, io::Error> fn blocking_io<F, T>(f: F) -> Poll<io::Result<T>>
where where
F: FnOnce() -> io::Result<T>, F: FnOnce() -> io::Result<T>,
{ {
match tokio_threadpool::blocking(f) { match tokio_threadpool::blocking(f) {
Ok(Ready(Ok(v))) => Ok(v.into()), Ready(Ok(v)) => Ready(v),
Ok(Ready(Err(err))) => Err(err), Ready(Err(_)) => Ready(Err(blocking_err())),
Ok(NotReady) => Ok(NotReady), Pending => Pending,
Err(_) => Err(blocking_err()),
} }
} }
@@ -90,13 +92,13 @@ where
F: FnOnce() -> io::Result<T>, F: FnOnce() -> io::Result<T>,
{ {
match tokio_threadpool::blocking(f) { match tokio_threadpool::blocking(f) {
Ok(Ready(Ok(v))) => Ok(v), Ready(Ok(Ok(v))) => Ok(v),
Ok(Ready(Err(err))) => { Ready(Ok(Err(err))) => {
debug_assert_ne!(err.kind(), WouldBlock); debug_assert_ne!(err.kind(), WouldBlock);
Err(err) Err(err)
} }
Ok(NotReady) => Err(WouldBlock.into()), Ready(Err(_)) => Err(blocking_err()),
Err(_) => Err(blocking_err()), Pending => Err(blocking_err()),
} }
} }
+6 -4
View File
@@ -1,8 +1,11 @@
use super::blocking_io; use super::blocking_io;
use futures::{Future, Poll};
use std::fs::{self, Metadata}; use std::fs::{self, Metadata};
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Queries the file system metadata for a path. /// Queries the file system metadata for a path.
pub fn metadata<P>(path: P) -> MetadataFuture<P> pub fn metadata<P>(path: P) -> MetadataFuture<P>
@@ -34,10 +37,9 @@ impl<P> Future for MetadataFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + 'static,
{ {
type Item = Metadata; type Output = io::Result<Metadata>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
blocking_io(|| fs::metadata(&self.path)) blocking_io(|| fs::metadata(&self.path))
} }
} }
+6 -4
View File
@@ -1,9 +1,12 @@
//! Unix-specific extensions to primitives in the `tokio_fs` module. //! Unix-specific extensions to primitives in the `tokio_fs` module.
use futures::{Future, Poll}; use std::future::Future;
use std::io; use std::io;
use std::os::unix::fs; use std::os::unix::fs;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Creates a new symbolic link on the filesystem. /// Creates a new symbolic link on the filesystem.
/// ///
@@ -42,10 +45,9 @@ where
P: AsRef<Path>, P: AsRef<Path>,
Q: AsRef<Path>, Q: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::symlink(&self.src, &self.dst)) crate::blocking_io(|| fs::symlink(&self.src, &self.dst))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll}; use std::future::Future;
use std::io; use std::io;
use std::os::windows::fs; use std::os::windows::fs;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Creates a new directory symlink on the filesystem. /// Creates a new directory symlink on the filesystem.
/// ///
@@ -41,10 +44,9 @@ where
P: AsRef<Path>, P: AsRef<Path>,
Q: AsRef<Path>, Q: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::symlink_dir(&self.src, &self.dst)) crate::blocking_io(|| fs::symlink_dir(&self.src, &self.dst))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll}; use std::future::Future;
use std::io; use std::io;
use std::os::windows::fs; use std::os::windows::fs;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Creates a new file symbolic link on the filesystem. /// Creates a new file symbolic link on the filesystem.
/// ///
@@ -41,10 +44,9 @@ where
P: AsRef<Path>, P: AsRef<Path>,
Q: AsRef<Path>, Q: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::symlink_file(&self.src, &self.dst)) crate::blocking_io(|| fs::symlink_file(&self.src, &self.dst))
} }
} }
+36 -23
View File
@@ -1,7 +1,11 @@
use crate::{file, File}; use crate::{file, File};
use futures::{try_ready, Async, Future, Poll}; use std::future::Future;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use std::{io, mem, path::Path}; use std::{io, mem, path::Path};
use tokio_io; use tokio_io;
use tokio_io::AsyncRead;
/// Creates a future which will open a file for reading and read the entire /// Creates a future which will open a file for reading and read the entire
/// contents into a buffer and return said buffer. /// contents into a buffer and return said buffer.
@@ -25,7 +29,7 @@ use tokio_io;
/// ``` /// ```
pub fn read<P>(path: P) -> ReadFile<P> pub fn read<P>(path: P) -> ReadFile<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
ReadFile { ReadFile {
state: State::Open(File::open(path)), state: State::Open(File::open(path)),
@@ -34,41 +38,50 @@ where
/// A future used to open a file and read its entire contents into a buffer. /// A future used to open a file and read its entire contents into a buffer.
#[derive(Debug)] #[derive(Debug)]
pub struct ReadFile<P: AsRef<Path> + Send + 'static> { pub struct ReadFile<P: AsRef<Path> + Send + Unpin + 'static> {
state: State<P>, state: State<P>,
} }
#[derive(Debug)] #[derive(Debug)]
enum State<P: AsRef<Path> + Send + 'static> { enum State<P: AsRef<Path> + Send + Unpin + 'static> {
Open(file::OpenFuture<P>), Open(file::OpenFuture<P>),
Metadata(file::MetadataFuture), Metadata(file::MetadataFuture),
Read(tokio_io::io::ReadToEnd<File>), Reading(Vec<u8>, usize, File),
Empty,
} }
impl<P: AsRef<Path> + Send + 'static> Future for ReadFile<P> { impl<P: AsRef<Path> + Send + Unpin + 'static> Future for ReadFile<P> {
type Item = Vec<u8>; type Output = io::Result<Vec<u8>>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let new_state = match &mut self.state { let inner = Pin::get_mut(self);
match &mut inner.state {
State::Open(ref mut open_file) => { State::Open(ref mut open_file) => {
let file = try_ready!(open_file.poll()); let file = ready!(Pin::new(open_file).poll(cx))?;
State::Metadata(file.metadata()) let new_state = State::Metadata(file.metadata());
mem::replace(&mut inner.state, new_state);
Pin::new(inner).poll(cx)
} }
State::Metadata(read_metadata) => { State::Metadata(read_metadata) => {
let (file, metadata) = try_ready!(read_metadata.poll()); let (file, metadata) = ready!(Pin::new(read_metadata).poll(cx))?;
let buf = Vec::with_capacity(metadata.len() as usize + 1); let buf = Vec::with_capacity(metadata.len() as usize + 1);
let read = tokio_io::io::read_to_end(file, buf); let new_state = State::Reading(buf, 0, file);
State::Read(read) mem::replace(&mut inner.state, new_state);
Pin::new(inner).poll(cx)
} }
State::Read(ref mut read) => { State::Reading(buf, ref mut pos, file) => {
let (_, buf) = try_ready!(read.poll()); let n = ready!(Pin::new(file).poll_read_buf(cx, buf))?;
return Ok(Async::Ready(buf)); *pos += n;
if *pos >= buf.len() {
match mem::replace(&mut inner.state, State::Empty) {
State::Reading(buf, _, _) => Poll::Ready(Ok(buf)),
_ => panic!(),
}
} else {
Poll::Pending
}
} }
}; State::Empty => panic!("poll a WriteFile after it's done"),
}
mem::replace(&mut self.state, new_state);
// Getting here means we transitionsed state. Must poll the new state.
self.poll()
} }
} }
+19 -12
View File
@@ -1,10 +1,14 @@
use futures::{Future, Poll, Stream}; use futures_core::stream::Stream;
use std::ffi::OsString; use std::ffi::OsString;
use std::fs::{self, DirEntry as StdDirEntry, FileType, Metadata, ReadDir as StdReadDir}; use std::fs::{self, DirEntry as StdDirEntry, FileType, Metadata, ReadDir as StdReadDir};
use std::future::Future;
use std::io; use std::io;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::fs::DirEntryExt; use std::os::unix::fs::DirEntryExt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Returns a stream over the entries within a directory. /// Returns a stream over the entries within a directory.
/// ///
@@ -40,10 +44,9 @@ impl<P> Future for ReadDirFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + 'static,
{ {
type Item = ReadDir; type Output = io::Result<ReadDir>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, io::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| Ok(ReadDir(fs::read_dir(&self.path)?))) crate::blocking_io(|| Ok(ReadDir(fs::read_dir(&self.path)?)))
} }
} }
@@ -68,15 +71,19 @@ where
pub struct ReadDir(StdReadDir); pub struct ReadDir(StdReadDir);
impl Stream for ReadDir { impl Stream for ReadDir {
type Item = DirEntry; type Item = io::Result<DirEntry>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
crate::blocking_io(|| match self.0.next() { let inner = Pin::get_mut(self);
match crate::blocking_io(|| match inner.0.next() {
Some(Err(err)) => Err(err), Some(Err(err)) => Err(err),
Some(Ok(item)) => Ok(Some(DirEntry(item))), Some(Ok(item)) => Ok(Some(Ok(DirEntry(item)))),
None => Ok(None), None => Ok(None),
}) }) {
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
Poll::Ready(Ok(v)) => Poll::Ready(v),
Poll::Pending => Poll::Pending,
}
} }
} }
@@ -181,7 +188,7 @@ impl DirEntry {
/// ///
/// tokio::run(fut); /// tokio::run(fut);
/// ``` /// ```
pub fn poll_metadata(&self) -> Poll<Metadata, io::Error> { pub fn poll_metadata(&self) -> Poll<io::Result<Metadata>> {
crate::blocking_io(|| self.0.metadata()) crate::blocking_io(|| self.0.metadata())
} }
@@ -213,7 +220,7 @@ impl DirEntry {
/// ///
/// tokio::run(fut); /// tokio::run(fut);
/// ``` /// ```
pub fn poll_file_type(&self) -> Poll<FileType, io::Error> { pub fn poll_file_type(&self) -> Poll<io::Result<FileType>> {
crate::blocking_io(|| self.0.file_type()) crate::blocking_io(|| self.0.file_type())
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Reads a symbolic link, returning the file that the link points to. /// Reads a symbolic link, returning the file that the link points to.
/// ///
@@ -34,10 +37,9 @@ impl<P> Future for ReadLinkFuture<P>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
type Item = PathBuf; type Output = io::Result<PathBuf>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::read_link(&self.path)) crate::blocking_io(|| fs::read_link(&self.path))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Removes an existing, empty directory. /// Removes an existing, empty directory.
/// ///
@@ -34,10 +37,9 @@ impl<P> Future for RemoveDirFuture<P>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::remove_dir(&self.path)) crate::blocking_io(|| fs::remove_dir(&self.path))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Removes a file from the filesystem. /// Removes a file from the filesystem.
/// ///
@@ -38,10 +41,9 @@ impl<P> Future for RemoveFileFuture<P>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::remove_file(&self.path)) crate::blocking_io(|| fs::remove_file(&self.path))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Rename a file or directory to a new name, replacing the original file if /// Rename a file or directory to a new name, replacing the original file if
/// `to` already exists. /// `to` already exists.
@@ -41,10 +44,9 @@ where
P: AsRef<Path>, P: AsRef<Path>,
Q: AsRef<Path>, Q: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::rename(&self.from, &self.to)) crate::blocking_io(|| fs::rename(&self.from, &self.to))
} }
} }
+6 -4
View File
@@ -1,7 +1,10 @@
use futures::{Future, Poll};
use std::fs; use std::fs;
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Changes the permissions found on a file or a directory. /// Changes the permissions found on a file or a directory.
/// ///
@@ -38,10 +41,9 @@ impl<P> Future for SetPermissionsFuture<P>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
type Item = (); type Output = io::Result<()>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
crate::blocking_io(|| fs::set_permissions(&self.path, self.perm.clone())) crate::blocking_io(|| fs::set_permissions(&self.path, self.perm.clone()))
} }
} }
+23 -3
View File
@@ -1,5 +1,7 @@
use futures::Poll;
use std::io::{self, Stderr as StdStderr, Write}; use std::io::{self, Stderr as StdStderr, Write};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use tokio_io::AsyncWrite; use tokio_io::AsyncWrite;
/// A handle to the standard error stream of a process. /// A handle to the standard error stream of a process.
@@ -36,7 +38,25 @@ impl Write for Stderr {
} }
impl AsyncWrite for Stderr { impl AsyncWrite for Stderr {
fn shutdown(&mut self) -> Poll<(), io::Error> { fn poll_write(
Ok(().into()) self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
match Pin::get_mut(self).write(buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self).flush() {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))
} }
} }
+12 -2
View File
@@ -1,4 +1,7 @@
use std::io::{self, Read, Stdin as StdStdin}; use std::io::{self, Read, Stdin as StdStdin};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use tokio_io::AsyncRead; use tokio_io::AsyncRead;
/// A handle to the standard input stream of a process. /// A handle to the standard input stream of a process.
@@ -37,7 +40,14 @@ impl Read for Stdin {
} }
impl AsyncRead for Stdin { impl AsyncRead for Stdin {
unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { fn poll_read(
false self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
match Pin::get_mut(self).read(buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
} }
} }
+23 -3
View File
@@ -1,5 +1,7 @@
use futures::Poll;
use std::io::{self, Stdout as StdStdout, Write}; use std::io::{self, Stdout as StdStdout, Write};
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use tokio_io::AsyncWrite; use tokio_io::AsyncWrite;
/// A handle to the standard output stream of a process. /// A handle to the standard output stream of a process.
@@ -36,7 +38,25 @@ impl Write for Stdout {
} }
impl AsyncWrite for Stdout { impl AsyncWrite for Stdout {
fn shutdown(&mut self) -> Poll<(), io::Error> { fn poll_write(
Ok(().into()) self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
match Pin::get_mut(self).write(buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self).flush() {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
other => Poll::Ready(other),
}
}
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))
} }
} }
+6 -4
View File
@@ -1,8 +1,11 @@
use super::blocking_io; use super::blocking_io;
use futures::{Future, Poll};
use std::fs::{self, Metadata}; use std::fs::{self, Metadata};
use std::future::Future;
use std::io; use std::io;
use std::path::Path; use std::path::Path;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
/// Queries the file system metadata for a path. /// Queries the file system metadata for a path.
/// ///
@@ -38,10 +41,9 @@ impl<P> Future for SymlinkMetadataFuture<P>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + 'static,
{ {
type Item = Metadata; type Output = io::Result<Metadata>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
blocking_io(|| fs::symlink_metadata(&self.path)) blocking_io(|| fs::symlink_metadata(&self.path))
} }
} }
+55 -24
View File
@@ -1,7 +1,11 @@
use crate::{file, File}; use crate::{file, File};
use futures::{try_ready, Async, Future, Poll}; use std::future::Future;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use std::{fmt, io, mem, path::Path}; use std::{fmt, io, mem, path::Path};
use tokio_io; use tokio_io;
use tokio_io::AsyncWrite;
/// Creates a future that will open a file for writing and write the entire /// Creates a future that will open a file for writing and write the entire
/// contents of `contents` to it. /// contents of `contents` to it.
@@ -25,9 +29,9 @@ use tokio_io;
/// ///
/// tokio::run(task); /// tokio::run(task);
/// ``` /// ```
pub fn write<P, C: AsRef<[u8]>>(path: P, contents: C) -> WriteFile<P, C> pub fn write<P, C: AsRef<[u8]> + Unpin>(path: P, contents: C) -> WriteFile<P, C>
where where
P: AsRef<Path> + Send + 'static, P: AsRef<Path> + Send + Unpin + 'static,
{ {
WriteFile { WriteFile {
state: State::Create(File::create(path), Some(contents)), state: State::Create(File::create(path), Some(contents)),
@@ -37,35 +41,62 @@ where
/// A future used to open a file for writing and write the entire contents /// A future used to open a file for writing and write the entire contents
/// of some data to it. /// of some data to it.
#[derive(Debug)] #[derive(Debug)]
pub struct WriteFile<P: AsRef<Path> + Send + 'static, C: AsRef<[u8]>> { pub struct WriteFile<P: AsRef<Path> + Send + Unpin + 'static, C: AsRef<[u8]> + Unpin> {
state: State<P, C>, state: State<P, C>,
} }
#[derive(Debug)] #[derive(Debug)]
enum State<P: AsRef<Path> + Send + 'static, C: AsRef<[u8]>> { enum State<P: AsRef<Path> + Send + Unpin + 'static, C: AsRef<[u8]> + Unpin> {
Create(file::CreateFuture<P>, Option<C>), Create(file::CreateFuture<P>, Option<C>),
Write(tokio_io::io::WriteAll<File, C>), Writing { f: File, buf: C, pos: usize },
Empty,
} }
impl<P: AsRef<Path> + Send + 'static, C: AsRef<[u8]> + fmt::Debug> Future for WriteFile<P, C> { fn zero_write() -> io::Error {
type Item = C; io::Error::new(io::ErrorKind::WriteZero, "zero-length write")
type Error = io::Error; }
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { impl<P: AsRef<Path> + Send + Unpin + 'static, C: AsRef<[u8]> + Unpin + fmt::Debug> Future
let new_state = match &mut self.state { for WriteFile<P, C>
State::Create(ref mut create_file, contents) => { {
let file = try_ready!(create_file.poll()); type Output = io::Result<C>;
let write = tokio_io::io::write_all(file, contents.take().unwrap());
State::Write(write)
}
State::Write(ref mut write) => {
let (_, contents) = try_ready!(write.poll());
return Ok(Async::Ready(contents));
}
};
mem::replace(&mut self.state, new_state); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// We just entered the Write state, need to poll it before returning. let inner = Pin::get_mut(self);
self.poll() match &mut inner.state {
State::Create(create_file, contents) => {
let file = ready!(Pin::new(create_file).poll(cx))?;
let contents = contents.take().unwrap();
let new_state = State::Writing {
f: file,
buf: contents,
pos: 0,
};
mem::replace(&mut inner.state, new_state);
// We just entered the Write state, need to poll it before returning.
return Pin::new(inner).poll(cx);
}
State::Empty => panic!("poll a WriteFile after it's done"),
_ => {}
}
match mem::replace(&mut inner.state, State::Empty) {
State::Writing {
mut f,
buf,
mut pos,
} => {
let buf_ref = buf.as_ref();
while pos < buf_ref.len() {
let n = ready!(Pin::new(&mut f).poll_write(cx, &buf_ref[pos..]))?;
pos += n;
if n == 0 {
return Poll::Ready(Err(zero_write()));
}
}
Poll::Ready(Ok(buf))
}
_ => panic!(),
}
} }
} }
+32 -13
View File
@@ -1,6 +1,8 @@
#![deny(warnings, rust_2018_idioms)] #![deny(warnings, rust_2018_idioms)]
#![feature(async_await)]
use futures::{Future, Stream}; use futures_util::future;
use futures_util::try_stream::TryStreamExt;
use std::fs; use std::fs;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use tempdir::TempDir; use tempdir::TempDir;
@@ -12,32 +14,44 @@ mod pool;
fn create() { fn create() {
let base_dir = TempDir::new("base").unwrap(); let base_dir = TempDir::new("base").unwrap();
let new_dir = base_dir.path().join("foo"); let new_dir = base_dir.path().join("foo");
let new_dir_2 = new_dir.clone();
pool::run({ create_dir(new_dir.clone()) }); pool::run(async move {
create_dir(new_dir).await?;
Ok(())
});
assert!(new_dir.is_dir()); assert!(new_dir_2.is_dir());
} }
#[test] #[test]
fn create_all() { fn create_all() {
let base_dir = TempDir::new("base").unwrap(); let base_dir = TempDir::new("base").unwrap();
let new_dir = base_dir.path().join("foo").join("bar"); let new_dir = base_dir.path().join("foo").join("bar");
let new_dir_2 = new_dir.clone();
pool::run({ create_dir_all(new_dir.clone()) }); pool::run(async move {
create_dir_all(new_dir).await?;
Ok(())
});
assert!(new_dir.is_dir()); assert!(new_dir_2.is_dir());
} }
#[test] #[test]
fn remove() { fn remove() {
let base_dir = TempDir::new("base").unwrap(); let base_dir = TempDir::new("base").unwrap();
let new_dir = base_dir.path().join("foo"); let new_dir = base_dir.path().join("foo");
let new_dir_2 = new_dir.clone();
fs::create_dir(new_dir.clone()).unwrap(); fs::create_dir(new_dir.clone()).unwrap();
pool::run({ remove_dir(new_dir.clone()) }); pool::run(async move {
remove_dir(new_dir).await?;
Ok(())
});
assert!(!new_dir.exists()); assert!(!new_dir_2.exists());
} }
#[test] #[test]
@@ -53,12 +67,17 @@ fn read() {
let f = files.clone(); let f = files.clone();
let p = p.to_path_buf(); let p = p.to_path_buf();
pool::run({
read_dir(p).flatten_stream().for_each(move |e| { pool::run(async move {
let s = e.file_name().to_str().unwrap().to_string(); let read_dir_fut = read_dir(p).await?;
f.lock().unwrap().push(s); read_dir_fut
Ok(()) .try_for_each(move |e| {
}) let s = e.file_name().to_str().unwrap().to_string();
f.lock().unwrap().push(s);
future::ok(())
})
.await?;
Ok(())
}); });
let mut files = files.lock().unwrap(); let mut files = files.lock().unwrap();
+61 -86
View File
@@ -1,13 +1,13 @@
#![deny(warnings, rust_2018_idioms)] #![deny(warnings, rust_2018_idioms)]
#![feature(async_await)]
use futures::future::poll_fn; use futures_util::future::poll_fn;
use futures::Future;
use rand::{distributions, thread_rng, Rng}; use rand::{distributions, thread_rng, Rng};
use std::fs; use std::fs;
use std::io::SeekFrom; use std::io::SeekFrom;
use tempfile::Builder as TmpBuilder; use tempfile::Builder as TmpBuilder;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio_fs::*; use tokio_fs::*;
use tokio_io::io;
mod pool; mod pool;
@@ -27,32 +27,25 @@ fn read_write() {
.collect::<String>() .collect::<String>()
.into(); .into();
pool::run({ let file_path_2 = file_path.clone();
let file_path = file_path.clone(); let contents_2 = contents.clone();
let contents = contents.clone();
File::create(file_path) pool::run(async move {
.and_then(|file| file.metadata()) let file = File::create(file_path).await?;
.inspect(|&(_, ref metadata)| assert!(metadata.is_file())) let (mut file, metadata) = file.metadata().await?;
.and_then(move |(file, _)| io::write_all(file, contents)) assert!(metadata.is_file());
.and_then(|(mut file, _)| poll_fn(move || file.poll_sync_all())) file.write(&contents).await?;
.then(|res| { poll_fn(move |_cx| file.poll_sync_all()).await?;
let _ = res.unwrap(); Ok(())
Ok(())
})
}); });
let dst = fs::read(&file_path).unwrap(); let dst = fs::read(&file_path_2).unwrap();
assert_eq!(dst, contents); assert_eq!(dst, contents_2);
pool::run({ pool::run(async move {
File::open(file_path) let buf = read(file_path_2).await?;
.and_then(|file| io::read_to_end(file, vec![])) assert_eq!(buf, contents_2);
.then(move |res| { Ok(())
let (_, buf) = res.unwrap();
assert_eq!(buf, contents);
Ok(())
})
}); });
} }
@@ -72,20 +65,21 @@ fn read_write_helpers() {
.collect::<String>() .collect::<String>()
.into(); .into();
pool::run(write(file_path.clone(), contents.clone()).then(|res| { let file_path_2 = file_path.clone();
let _ = res.unwrap(); let contents_2 = contents.clone();
pool::run(async move {
write(file_path, contents).await?;
Ok(()) Ok(())
})); });
let dst = fs::read(&file_path).unwrap(); let dst = fs::read(&file_path_2).unwrap();
assert_eq!(dst, contents); assert_eq!(dst, contents_2);
pool::run({ pool::run(async move {
read(file_path).then(move |res| { let buf = read(file_path_2).await?;
let buf = res.unwrap(); assert_eq!(buf, contents_2);
assert_eq!(buf, contents); Ok(())
Ok(())
})
}); });
} }
@@ -97,22 +91,12 @@ fn metadata() {
.unwrap(); .unwrap();
let file_path = dir.path().join("metadata.txt"); let file_path = dir.path().join("metadata.txt");
pool::run({ pool::run(async move {
let file_path = file_path.clone(); assert!(tokio_fs::metadata(file_path.clone()).await.is_err());
let file_path2 = file_path.clone(); File::create(file_path.clone()).await?;
let file_path3 = file_path.clone(); let metadata = tokio_fs::metadata(file_path.clone()).await?;
assert!(metadata.is_file());
tokio_fs::metadata(file_path) Ok(())
.then(|r| {
let _ = r.err().unwrap();
Ok(())
})
.and_then(|_| File::create(file_path2))
.and_then(|_| tokio_fs::metadata(file_path3))
.then(|r| {
assert!(r.unwrap().is_file());
Ok(())
})
}); });
} }
@@ -124,28 +108,24 @@ fn seek() {
.unwrap(); .unwrap();
let file_path = dir.path().join("seek.txt"); let file_path = dir.path().join("seek.txt");
pool::run({ pool::run(async move {
OpenOptions::new() let mut file = OpenOptions::new()
.create(true) .create(true)
.read(true) .read(true)
.write(true) .write(true)
.open(file_path) .open(file_path)
.and_then(|file| io::write_all(file, "Hello, world!")) .await
.and_then(|(file, _)| file.seek(SeekFrom::End(-6))) .unwrap();
.and_then(|(file, _)| io::read_exact(file, vec![0; 5])) assert!(file.write(b"Hello, world!").await.is_ok());
.and_then(|(file, buf)| { let mut file = file.seek(SeekFrom::End(-6)).await.unwrap().0;
assert_eq!(buf, b"world"); let mut buf = vec![0; 5];
file.seek(SeekFrom::Start(0)) assert!(file.read(buf.as_mut()).await.is_ok());
}) assert_eq!(buf, b"world");
.and_then(|(file, _)| io::read_exact(file, vec![0; 5])) let mut file = file.seek(SeekFrom::Start(0)).await.unwrap().0;
.and_then(|(_, buf)| { let mut buf = vec![0; 5];
assert_eq!(buf, b"Hello"); assert!(file.read(buf.as_mut()).await.is_ok());
Ok(()) assert_eq!(buf, b"Hello");
}) Ok(())
.then(|r| {
let _ = r.unwrap();
Ok(())
})
}); });
} }
@@ -158,24 +138,19 @@ fn clone() {
.tempdir() .tempdir()
.unwrap(); .unwrap();
let file_path = dir.path().join("clone.txt"); let file_path = dir.path().join("clone.txt");
let file_path_2 = file_path.clone();
pool::run( pool::run(async move {
File::create(file_path.clone()) let file = File::create(file_path.clone()).await.unwrap();
.and_then(|file| { let (mut file, mut clone) = file.try_clone().await.unwrap();
file.try_clone() assert!(AsyncWriteExt::write(&mut file, b"clone ").await.is_ok());
.map_err(|(_file, err)| err) assert!(AsyncWriteExt::write(&mut clone, b"successful")
.and_then(|(file, clone)| { .await
io::write_all(file, "clone ") .is_ok());
.and_then(|_| io::write_all(clone, "successful")) Ok(())
}) });
})
.then(|res| {
let _ = res.unwrap();
Ok(())
}),
);
let mut file = std::fs::File::open(&file_path).unwrap(); let mut file = std::fs::File::open(&file_path_2).unwrap();
let mut dst = vec![]; let mut dst = vec![];
file.read_to_end(&mut dst).unwrap(); file.read_to_end(&mut dst).unwrap();
+24 -6
View File
@@ -1,4 +1,5 @@
#![deny(warnings, rust_2018_idioms)] #![deny(warnings, rust_2018_idioms)]
#![feature(async_await)]
use std::fs; use std::fs;
use std::io::prelude::*; use std::io::prelude::*;
@@ -19,7 +20,12 @@ fn test_hard_link() {
file.write_all(b"hello").unwrap(); file.write_all(b"hello").unwrap();
} }
pool::run({ hard_link(src, dst.clone()) }); let dst_2 = dst.clone();
pool::run(async move {
assert!(hard_link(src, dst_2.clone()).await.is_ok());
Ok(())
});
let mut content = String::new(); let mut content = String::new();
@@ -35,8 +41,6 @@ fn test_hard_link() {
#[cfg(unix)] #[cfg(unix)]
#[test] #[test]
fn test_symlink() { fn test_symlink() {
use futures::Future;
let dir = TempDir::new("base").unwrap(); let dir = TempDir::new("base").unwrap();
let src = dir.path().join("src.txt"); let src = dir.path().join("src.txt");
let dst = dir.path().join("dst.txt"); let dst = dir.path().join("dst.txt");
@@ -46,7 +50,15 @@ fn test_symlink() {
file.write_all(b"hello").unwrap(); file.write_all(b"hello").unwrap();
} }
pool::run({ os::unix::symlink(src.clone(), dst.clone()) }); let src_2 = src.clone();
let dst_2 = dst.clone();
pool::run(async move {
assert!(os::unix::symlink(src_2.clone(), dst_2.clone())
.await
.is_ok());
Ok(())
});
let mut content = String::new(); let mut content = String::new();
@@ -58,6 +70,12 @@ fn test_symlink() {
assert!(content == "hello"); assert!(content == "hello");
pool::run({ read_link(dst.clone()).map(move |x| assert!(x == src)) }); pool::run(async move {
pool::run({ symlink_metadata(dst.clone()).map(move |x| assert!(x.file_type().is_symlink())) }); let read = read_link(dst.clone()).await.unwrap();
assert!(read == src);
let symlink_meta = symlink_metadata(dst.clone()).await.unwrap();
assert!(symlink_meta.file_type().is_symlink());
Ok(())
});
} }
+9 -7
View File
@@ -1,17 +1,19 @@
use futures;
use tokio_threadpool; use tokio_threadpool;
use self::tokio_threadpool::Builder; use self::tokio_threadpool::Builder;
use futures::sync::oneshot; use std::future::Future;
use futures::Future;
use std::io; use std::io;
use std::sync::mpsc;
pub fn run<F>(f: F) pub fn run<F>(f: F)
where where
F: Future<Item = (), Error = io::Error> + Send + 'static, F: Future<Output = io::Result<()>> + Send + 'static,
{ {
let pool = Builder::new().pool_size(1).build(); let pool = Builder::new().pool_size(1).build();
let (tx, rx) = oneshot::channel::<()>(); let (tx, rx) = mpsc::channel();
pool.spawn(f.then(|_| tx.send(()))); pool.spawn(async move {
rx.wait().unwrap() f.await.unwrap();
tx.send(()).unwrap();
});
rx.recv().unwrap()
} }
+1 -1
View File
@@ -68,7 +68,7 @@ bytes = { version = "0.4", optional = true }
num_cpus = { version = "1.8.0", optional = true } num_cpus = { version = "1.8.0", optional = true }
tokio-codec = { version = "0.2.0", optional = true, path = "../tokio-codec" } tokio-codec = { version = "0.2.0", optional = true, path = "../tokio-codec" }
tokio-current-thread = { version = "0.2.0", optional = true, path = "../tokio-current-thread" } tokio-current-thread = { version = "0.2.0", optional = true, path = "../tokio-current-thread" }
#tokio-fs = { version = "0.2.0", optional = true, path = "../tokio-fs" } tokio-fs = { version = "0.2.0", optional = true, path = "../tokio-fs" }
tokio-io = { version = "0.2.0", optional = true, path = "../tokio-io" } tokio-io = { version = "0.2.0", optional = true, path = "../tokio-io" }
tokio-executor = { version = "0.2.0", optional = true, path = "../tokio-executor" } tokio-executor = { version = "0.2.0", optional = true, path = "../tokio-executor" }
tokio-macros = { version = "0.2.0", optional = true, path = "../tokio-macros" } tokio-macros = { version = "0.2.0", optional = true, path = "../tokio-macros" }