fs: add CloneFuture for File::try_clone (#850)

This commit is contained in:
Kevin M Granger
2019-02-20 12:25:50 -08:00
committed by Carl Lerche
parent 3d787b16c7
commit ab206b976c
3 changed files with 103 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
use super::File;
use futures::{Future, Poll};
use std::io;
/// Future returned by `File::try_clone`.
///
/// Clones a file handle into two file handles.
///
/// # Panics
///
/// Will panic if polled after returning an item or error.
#[derive(Debug)]
pub struct CloneFuture {
file: Option<File>,
}
impl CloneFuture {
pub(crate) fn new(file: File) -> Self {
Self { file: Some(file) }
}
}
impl Future for CloneFuture {
type Item = (File, File);
type Error = (File, io::Error);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.file
.as_mut()
.expect("Cannot poll `CloneFuture` after it resolves")
.poll_try_clone()
.map(|inner| inner.map(|cloned| (self.file.take().unwrap(), cloned)))
.map_err(|err| (self.file.take().unwrap(), err))
}
}
+34
View File
@@ -2,12 +2,14 @@
//!
//! [`File`]: file/struct.File.html
mod clone;
mod create;
mod metadata;
mod open;
mod open_options;
mod seek;
pub use self::clone::CloneFuture;
pub use self::create::CreateFuture;
pub use self::metadata::MetadataFuture;
pub use self::open::OpenFuture;
@@ -407,6 +409,38 @@ impl File {
})
}
/// Create a new `File` instance that shares the same underlying file handle
/// as the existing `File` instance. Reads, writes, and seeks will affect both
/// File instances simultaneously.
///
/// # Examples
/// ```no_run
/// # extern crate tokio;
/// use tokio::prelude::Future;
///
/// fn main() {
/// let task = tokio::fs::File::create("foo.txt")
/// .and_then(|file| {
/// file.try_clone()
/// .map(|(file, clone)| {
/// // do something with the file and the clone
/// # println!("{:?} {:?}", file, clone);
/// })
/// .map_err(|(file, err)| {
/// // you get the original file back if there's an error
/// # println!("{:?}", file);
/// err
/// })
/// })
/// .map_err(|err| eprintln!("IO error: {:?}", err));
///
/// tokio::run(task);
/// }
/// ```
pub fn try_clone(self) -> CloneFuture {
CloneFuture::new(self)
}
/// Changes the permissions on the underlying file.
///
/// # Platform-specific behavior
+32
View File
@@ -125,3 +125,35 @@ fn seek() {
})
});
}
#[test]
fn clone() {
let dir = TmpBuilder::new()
.prefix("tokio-fs-tests")
.tempdir()
.unwrap();
let file_path = dir.path().join("clone.txt");
pool::run(
File::create(file_path.clone())
.and_then(|file| {
file.try_clone()
.map_err(|(_file, err)| err)
.and_then(|(file, clone)| {
io::write_all(file, "clone ")
.and_then(|_| io::write_all(clone, "successful"))
})
})
.then(|res| {
let _ = res.unwrap();
Ok(())
}),
);
let mut file = StdFile::open(&file_path).unwrap();
let mut dst = vec![];
file.read_to_end(&mut dst).unwrap();
assert_eq!(dst, b"clone successful")
}