diff options
Diffstat (limited to 'third_party/rust/tokio-fs')
33 files changed, 1939 insertions, 0 deletions
diff --git a/third_party/rust/tokio-fs/.cargo-checksum.json b/third_party/rust/tokio-fs/.cargo-checksum.json new file mode 100644 index 0000000000..7b7e36abd7 --- /dev/null +++ b/third_party/rust/tokio-fs/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d07abfd675dfa12dda0f46b7ad56fc0f6da677a26a6cfa0531e623e103b68abd","Cargo.toml":"69399fbac7423aa14484b8e89cb8fd187ae7277a024378fd7d74fb7eff033f1c","LICENSE":"4899c290472c872cf8a1904a60e73ec58a1bc1db2e20bc143aa3d1498be49c96","README.md":"2b714a9a29f09a4555b1ee7b7ef27bfd12522c98589eb94f59ef9c315700781b","examples/std-echo.rs":"66927bb61b29565deedbb4fe4a6271a624fed4baf5a5b41bb040059c71b2ad7b","src/create_dir.rs":"e2c4f913fa8d89d10bc2c549dc25c70ec1a119fc7e63909729c19d74a672a80d","src/create_dir_all.rs":"c873c34f00a7075cfeece7fdf76fc85e70871f776ff3811c6d3e8a6b84dd799a","src/file/create.rs":"ad7ef003a65a5bbcd16f28104f19bd7187fa3617c488dd0edb4070074919300b","src/file/metadata.rs":"bddcee02d00a05c272d5d9e2def359f51270d4a25be6630a9c52e3179ed192da","src/file/mod.rs":"fcfb0a882a08600be841d0a40d6746d6c82cf394de8b57e1c21803ea1f1bfcb4","src/file/open.rs":"5012c37d58048606e009bc4b7f7c5095167ce1f5c3dfc9a03e4b1762e83a6de3","src/file/open_options.rs":"0a6ae78653ae200b385b524fe5bbdf069f53a9d7fb087daa11f0bc28759dfc05","src/file/seek.rs":"c1cfe4a228b518e9a7fc3e09567b6ff290b116a7d717f99cdafcd2de13581411","src/hard_link.rs":"3cd1baeed52abc1cb45801d83872ce77df9ea8d037735829b07a1bea07e69fc1","src/lib.rs":"6b8573d70b4b7968d30964803791cf14dfcd4386a74a6170943b3c848f61ab5a","src/metadata.rs":"3882111af4cdbed2eec93ce7fa66b392867833bb55267015e4956d7a2aaa7442","src/os/mod.rs":"9165d5841d1503608049459154c9e2f020ec8d70dde6c00e25833db12addb572","src/os/unix.rs":"44588f808a79a99614812a181ad20d978a1db8b86bf2d95b4fbf77036f15f4ef","src/os/windows/mod.rs":"09c28e0926a2a99ed46fa53f878b1bd84ea73f522acbb40ca63983477922f365","src/os/windows/symlink_dir.rs":"cd41c3d31e9e1a17cf1c21a9c64741d02181242407410ebd65dc4ce81f5c4b8e","src/os/windows/symlink_file.rs":"b9cb16bd85ab90af67baafe6243615b8b3d82348771bd49956a232e9b97b0560","src/read_dir.rs":"138e9d05ec30326ad151b4c1cf1f134f8c3337d9fcf4f0175f51560eb6ee5b97","src/read_link.rs":"ad85fdee77a8ee2ffc1beb35a4a7e7571fc637e1a367d7cf3346ea67673f1edd","src/remove_dir.rs":"21e1e346b53f50d8e8a82c9143bba566a418e09eb13ba8d6c9a6d9155689355b","src/remove_file.rs":"9474d73a6f26ccd1b70da120d2751a1115cc5431983c72f69346b092993b5acc","src/rename.rs":"2eb8fdfcf5b38c059a12abe0443ff65d200b2b44a9b0130b774d417e8949e313","src/set_permissions.rs":"bde74d8d83f8113ef8a1883e1b09a67c26259ddf749f1e11ad2ab2c284222118","src/stderr.rs":"0a84ebdab07500a0b71c03076ccaaf511e093ef77af3b722a0f0acdf91b94034","src/stdin.rs":"ba7b0e4d08dc10743f1139a4aff13d74c564ae9e5dfef8a07388b4b9f75e2c3b","src/stdout.rs":"6f5e807c1bfc90655d364dd2a2d49f8895d86af9ad5cfdf8196a00bdf6d247fb","src/symlink_metadata.rs":"ce4345c5b35f48bcc40b0c0e7c84f3574540a044576fd9837f15724d266480de","tests/file.rs":"1b74b9e1ee6ab62d0db9d900ad497fd42464bb40bcce95453fad67969d9d1ddc"},"package":"b5cbe4ca6e71cb0b62a66e4e6f53a8c06a6eefe46cc5f665ad6f274c9906f135"}
\ No newline at end of file diff --git a/third_party/rust/tokio-fs/CHANGELOG.md b/third_party/rust/tokio-fs/CHANGELOG.md new file mode 100644 index 0000000000..197d4a8937 --- /dev/null +++ b/third_party/rust/tokio-fs/CHANGELOG.md @@ -0,0 +1,18 @@ +# 0.1.3 (August 6, 2018) + +* Add async equivalents to most of `std::fs` (#494). + +# 0.1.2 (July 11, 2018) + +* Add `metadata` and `File::metadata` ([#433](https://github.com/tokio-rs/tokio/pull/433), [#385](https://github.com/tokio-rs/tokio/pull/385)) +* Add `File::seek` ([#434](https://github.com/tokio-rs/tokio/pull/434)) + +# 0.1.1 (June 13, 2018) + +* Add `OpenOptions` ([#390](https://github.com/tokio-rs/tokio/pull/390)) +* Add `into_std` to `File` ([#403](https://github.com/tokio-rs/tokio/pull/403)) +* Use `tokio-codec` in examples + +# 0.1.0 (May 2, 2018) + +* Initial release diff --git a/third_party/rust/tokio-fs/Cargo.toml b/third_party/rust/tokio-fs/Cargo.toml new file mode 100644 index 0000000000..fd5e59434e --- /dev/null +++ b/third_party/rust/tokio-fs/Cargo.toml @@ -0,0 +1,46 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "tokio-fs" +version = "0.1.3" +authors = ["Carl Lerche <me@carllerche.com>"] +description = "Filesystem API for Tokio.\n" +homepage = "https://tokio.rs" +documentation = "https://docs.rs/tokio-fs/0.1" +readme = "README.md" +keywords = ["tokio", "futures", "fs", "file", "async"] +categories = ["asynchronous", "network-programming", "filesystem"] +license = "MIT" +repository = "https://github.com/tokio-rs/tokio" +[dependencies.futures] +version = "0.1.21" + +[dependencies.tokio-io] +version = "0.1.6" + +[dependencies.tokio-threadpool] +version = "0.1.3" +[dev-dependencies.rand] +version = "0.4.2" + +[dev-dependencies.tempdir] +version = "0.3.7" + +[dev-dependencies.tokio] +version = "0.1.7" + +[dev-dependencies.tokio-codec] +version = "0.1.0" + +[dev-dependencies.tokio-io] +version = "0.1.6" diff --git a/third_party/rust/tokio-fs/LICENSE b/third_party/rust/tokio-fs/LICENSE new file mode 100644 index 0000000000..38c1e27b8e --- /dev/null +++ b/third_party/rust/tokio-fs/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2018 Tokio Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/tokio-fs/README.md b/third_party/rust/tokio-fs/README.md new file mode 100644 index 0000000000..f359d7676a --- /dev/null +++ b/third_party/rust/tokio-fs/README.md @@ -0,0 +1,19 @@ +# Tokio FS + +Asynchronous filesystem manipulation operations (and stdin, stdout, stderr). + +[Documentation](https://tokio-rs.github.io/tokio/tokio_fs/) + +## Overview + +This crate provides filesystem manipulation facilities for usage with Tokio. + +## License + +This project is licensed under the [MIT license](LICENSE). + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Tokio by you, shall be licensed as MIT, without any additional +terms or conditions. diff --git a/third_party/rust/tokio-fs/examples/std-echo.rs b/third_party/rust/tokio-fs/examples/std-echo.rs new file mode 100644 index 0000000000..83efa66e58 --- /dev/null +++ b/third_party/rust/tokio-fs/examples/std-echo.rs @@ -0,0 +1,48 @@ +//! Echo everything received on STDIN to STDOUT. +#![deny(deprecated, warnings)] + +extern crate futures; +extern crate tokio_fs; +extern crate tokio_codec; +extern crate tokio_threadpool; + +use tokio_fs::{stdin, stdout, stderr}; +use tokio_codec::{FramedRead, FramedWrite, LinesCodec}; +use tokio_threadpool::Builder; + +use futures::{Future, Stream, Sink}; + +use std::io; + +pub fn main() { + let pool = Builder::new() + .pool_size(1) + .build(); + + pool.spawn({ + let input = FramedRead::new(stdin(), LinesCodec::new()); + + let output = FramedWrite::new(stdout(), LinesCodec::new()) + .with(|line: String| { + let mut out = "OUT: ".to_string(); + out.push_str(&line); + Ok::<_, io::Error>(out) + }); + + let error = FramedWrite::new(stderr(), LinesCodec::new()) + .with(|line: String| { + let mut out = "ERR: ".to_string(); + out.push_str(&line); + Ok::<_, io::Error>(out) + }); + + let dst = output.fanout(error); + + input + .forward(dst) + .map(|_| ()) + .map_err(|e| panic!("io error = {:?}", e)) + }); + + pool.shutdown_on_idle().wait().unwrap(); +} diff --git a/third_party/rust/tokio-fs/src/create_dir.rs b/third_party/rust/tokio-fs/src/create_dir.rs new file mode 100644 index 0000000000..a174a5d97f --- /dev/null +++ b/third_party/rust/tokio-fs/src/create_dir.rs @@ -0,0 +1,46 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Creates a new, empty directory at the provided path +/// +/// This is an async version of [`std::fs::create_dir`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.create_dir.html +pub fn create_dir<P: AsRef<Path>>(path: P) -> CreateDirFuture<P> { + CreateDirFuture::new(path) +} + +/// Future returned by `create_dir`. +#[derive(Debug)] +pub struct CreateDirFuture<P> +where + P: AsRef<Path> +{ + path: P, +} + +impl<P> CreateDirFuture<P> +where + P: AsRef<Path> +{ + fn new(path: P) -> CreateDirFuture<P> { + CreateDirFuture { + path: path, + } + } +} + +impl<P> Future for CreateDirFuture<P> +where + P: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::create_dir(&self.path) ) + } +} diff --git a/third_party/rust/tokio-fs/src/create_dir_all.rs b/third_party/rust/tokio-fs/src/create_dir_all.rs new file mode 100644 index 0000000000..3e32480673 --- /dev/null +++ b/third_party/rust/tokio-fs/src/create_dir_all.rs @@ -0,0 +1,47 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Recursively create a directory and all of its parent components if they +/// are missing. +/// +/// This is an async version of [`std::fs::create_dir_all`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.create_dir_all.html +pub fn create_dir_all<P: AsRef<Path>>(path: P) -> CreateDirAllFuture<P> { + CreateDirAllFuture::new(path) +} + +/// Future returned by `create_dir_all`. +#[derive(Debug)] +pub struct CreateDirAllFuture<P> +where + P: AsRef<Path> +{ + path: P, +} + +impl<P> CreateDirAllFuture<P> +where + P: AsRef<Path> +{ + fn new(path: P) -> CreateDirAllFuture<P> { + CreateDirAllFuture { + path: path, + } + } +} + +impl<P> Future for CreateDirAllFuture<P> +where + P: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::create_dir_all(&self.path) ) + } +} diff --git a/third_party/rust/tokio-fs/src/file/create.rs b/third_party/rust/tokio-fs/src/file/create.rs new file mode 100644 index 0000000000..4027418563 --- /dev/null +++ b/third_party/rust/tokio-fs/src/file/create.rs @@ -0,0 +1,37 @@ +use super::File; + +use futures::{Future, Poll}; + +use std::fs::File as StdFile; +use std::io; +use std::path::Path; + +/// Future returned by `File::create` and resolves to a `File` instance. +#[derive(Debug)] +pub struct CreateFuture<P> { + path: P, +} + +impl<P> CreateFuture<P> +where P: AsRef<Path> + Send + 'static, +{ + pub(crate) fn new(path: P) -> Self { + CreateFuture { path } + } +} + +impl<P> Future for CreateFuture<P> +where P: AsRef<Path> + Send + 'static, +{ + type Item = File; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + let std = try_ready!(::blocking_io(|| { + StdFile::create(&self.path) + })); + + let file = File::from_std(std); + Ok(file.into()) + } +} diff --git a/third_party/rust/tokio-fs/src/file/metadata.rs b/third_party/rust/tokio-fs/src/file/metadata.rs new file mode 100644 index 0000000000..b55ca103c1 --- /dev/null +++ b/third_party/rust/tokio-fs/src/file/metadata.rs @@ -0,0 +1,39 @@ +use super::File; + +use futures::{Future, Poll}; + +use std::fs::File as StdFile; +use std::fs::Metadata; +use std::io; + +const POLL_AFTER_RESOLVE: &str = "Cannot poll MetadataFuture after it resolves"; + +/// Future returned by `File::metadata` and resolves to a `(Metadata, File)` instance. +#[derive(Debug)] +pub struct MetadataFuture { + file: Option<File>, +} + +impl MetadataFuture { + pub(crate) fn new(file: File) -> Self { + MetadataFuture { file: Some(file) } + } + + fn std(&mut self) -> &mut StdFile { + self.file.as_mut().expect(POLL_AFTER_RESOLVE).std() + } +} + +impl Future for MetadataFuture { + type Item = (File, Metadata); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + let metadata = try_ready!(::blocking_io(|| { + StdFile::metadata(self.std()) + })); + + let file = self.file.take().expect(POLL_AFTER_RESOLVE); + Ok((file, metadata).into()) + } +} diff --git a/third_party/rust/tokio-fs/src/file/mod.rs b/third_party/rust/tokio-fs/src/file/mod.rs new file mode 100644 index 0000000000..c3ae431121 --- /dev/null +++ b/third_party/rust/tokio-fs/src/file/mod.rs @@ -0,0 +1,243 @@ +//! Types for working with [`File`]. +//! +//! [`File`]: file/struct.File.html + +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}; + +use futures::Poll; + +use std::fs::{File as StdFile, Metadata, Permissions}; +use std::io::{self, Read, Write, Seek}; +use std::path::Path; + +/// A reference to an open file on the filesystem. +/// +/// This is a specialized version of [`std::fs::File`][std] for usage from the +/// Tokio runtime. +/// +/// An instance of a `File` can be read and/or written depending on what options +/// it was opened with. Files also implement Seek to alter the logical cursor +/// that the file contains internally. +/// +/// Files are automatically closed when they go out of scope. +/// +/// [std]: https://doc.rust-lang.org/std/fs/struct.File.html +#[derive(Debug)] +pub struct File { + std: Option<StdFile>, +} + +impl File { + /// Attempts to open a file in read-only mode. + /// + /// See [`OpenOptions`] for more details. + /// + /// [`OpenOptions`]: struct.OpenOptions.html + /// + /// # Errors + /// + /// `OpenFuture` results in an error if called from outside of the Tokio + /// runtime or if the underlying [`open`] call results in an error. + /// + /// [`open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open + pub fn open<P>(path: P) -> OpenFuture<P> + where P: AsRef<Path> + Send + 'static, + { + OpenOptions::new().read(true).open(path) + } + + /// Opens a file in write-only mode. + /// + /// This function will create a file if it does not exist, and will truncate + /// it if it does. + /// + /// See [`OpenOptions`] for more details. + /// + /// [`OpenOptions`]: struct.OpenOptions.html + /// + /// # Errors + /// + /// `CreateFuture` results in an error if called from outside of the Tokio + /// runtime or if the underlying [`create`] call results in an error. + /// + /// [`create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create + pub fn create<P>(path: P) -> CreateFuture<P> + where P: AsRef<Path> + Send + 'static, + { + CreateFuture::new(path) + } + + /// Convert a [`std::fs::File`][std] to a `tokio_fs::File`. + /// + /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html + pub(crate) fn from_std(std: StdFile) -> File { + File { std: Some(std) } + } + + /// Seek to an offset, in bytes, in a stream. + /// + /// A seek beyond the end of a stream is allowed, but implementation + /// defined. + /// + /// If the seek operation completed successfully, this method returns the + /// new position from the start of the stream. That position can be used + /// later with `SeekFrom::Start`. + /// + /// # Errors + /// + /// Seeking to a negative offset is considered an error. + pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error> { + ::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 + /// filesystem before returning. + pub fn poll_sync_all(&mut self) -> Poll<(), io::Error> { + ::blocking_io(|| self.std().sync_all()) + } + + /// This function is similar to `poll_sync_all`, except that it may not + /// synchronize file metadata to the filesystem. + /// + /// This is intended for use cases that must synchronize content, but don't + /// need the metadata on disk. The goal of this method is to reduce disk + /// operations. + /// + /// Note that some platforms may simply implement this in terms of `poll_sync_all`. + pub fn poll_sync_data(&mut self) -> Poll<(), io::Error> { + ::blocking_io(|| self.std().sync_data()) + } + + /// Truncates or extends the underlying file, updating the size of this file to become size. + /// + /// If the size is less than the current file's size, then the file will be + /// shrunk. If it is greater than the current file's size, then the file + /// will be extended to size and have all of the intermediate data filled in + /// with 0s. + /// + /// # Errors + /// + /// This function will return an error if the file is not opened for + /// writing. + pub fn poll_set_len(&mut self, size: u64) -> Poll<(), io::Error> { + ::blocking_io(|| self.std().set_len(size)) + } + + /// Queries metadata about the underlying file. + pub fn metadata(self) -> MetadataFuture { + MetadataFuture::new(self) + } + + /// Queries metadata about the underlying file. + pub fn poll_metadata(&mut self) -> Poll<Metadata, io::Error> { + ::blocking_io(|| self.std().metadata()) + } + + /// 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. + pub fn poll_try_clone(&mut self) -> Poll<File, io::Error> { + ::blocking_io(|| { + let std = self.std().try_clone()?; + Ok(File::from_std(std)) + }) + } + + /// Changes the permissions on the underlying file. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `fchmod` function on Unix and + /// the `SetFileInformationByHandle` function on Windows. Note that, this + /// [may change in the future][changes]. + /// + /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior + /// + /// # Errors + /// + /// This function will return an error if the user lacks permission change + /// attributes on the underlying file. It may also return an error in other + /// os-specific unspecified cases. + pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error> { + ::blocking_io(|| self.std().set_permissions(perm)) + } + + /// Destructures the `tokio_fs::File` into a [`std::fs::File`][std]. + /// + /// # Panics + /// + /// This function will panic if `shutdown` has been called. + /// + /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html + pub fn into_std(mut self) -> StdFile { + self.std.take().expect("`File` instance already shutdown") + } + + fn std(&mut self) -> &mut StdFile { + self.std.as_mut().expect("`File` instance already shutdown") + } +} + +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + ::would_block(|| self.std().read(buf)) + } +} + +impl AsyncRead for File { + unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { + false + } +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + ::would_block(|| self.std().write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + ::would_block(|| self.std().flush()) + } +} + +impl AsyncWrite for File { + fn shutdown(&mut self) -> Poll<(), io::Error> { + ::blocking_io(|| { + self.std = None; + Ok(()) + }) + } +} + +impl Drop for File { + fn drop(&mut self) { + if let Some(_std) = self.std.take() { + // This is probably fine as closing a file *shouldn't* be a blocking + // operation. That said, ideally `shutdown` is called first. + } + } +} diff --git a/third_party/rust/tokio-fs/src/file/open.rs b/third_party/rust/tokio-fs/src/file/open.rs new file mode 100644 index 0000000000..197ec237af --- /dev/null +++ b/third_party/rust/tokio-fs/src/file/open.rs @@ -0,0 +1,38 @@ +use super::File; + +use futures::{Future, Poll}; + +use std::fs::OpenOptions as StdOpenOptions; +use std::io; +use std::path::Path; + +/// Future returned by `File::open` and resolves to a `File` instance. +#[derive(Debug)] +pub struct OpenFuture<P> { + options: StdOpenOptions, + path: P, +} + +impl<P> OpenFuture<P> +where P: AsRef<Path> + Send + 'static, +{ + pub(crate) fn new(options: StdOpenOptions, path: P) -> Self { + OpenFuture { options, path } + } +} + +impl<P> Future for OpenFuture<P> +where P: AsRef<Path> + Send + 'static, +{ + type Item = File; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + let std = try_ready!(::blocking_io(|| { + self.options.open(&self.path) + })); + + let file = File::from_std(std); + Ok(file.into()) + } +} diff --git a/third_party/rust/tokio-fs/src/file/open_options.rs b/third_party/rust/tokio-fs/src/file/open_options.rs new file mode 100644 index 0000000000..99cc71c5b0 --- /dev/null +++ b/third_party/rust/tokio-fs/src/file/open_options.rs @@ -0,0 +1,103 @@ +use super::OpenFuture; + +use std::convert::From; +use std::fs::OpenOptions as StdOpenOptions; +use std::path::Path; + +/// Options and flags which can be used to configure how a file is opened. +/// +/// This is a specialized version of [`std::fs::OpenOptions`] for usage from +/// the Tokio runtime. +/// +/// `From<std::fs::OpenOptions>` is implemented for more advanced configuration +/// than the methods provided here. +/// +/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html +#[derive(Clone, Debug)] +pub struct OpenOptions(StdOpenOptions); + +impl OpenOptions { + /// Creates a blank new set of options ready for configuration. + /// + /// All options are initially set to `false`. + /// + /// # Examples + /// + /// ```ignore + /// use tokio::fs::OpenOptions; + /// + /// let mut options = OpenOptions::new(); + /// let future = options.read(true).open("foo.txt"); + /// ``` + pub fn new() -> OpenOptions { + OpenOptions(StdOpenOptions::new()) + } + + /// See the underlying [`read`] call for details. + /// + /// [`read`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.read + pub fn read(&mut self, read: bool) -> &mut OpenOptions { + self.0.read(read); + self + } + + /// See the underlying [`write`] call for details. + /// + /// [`write`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.write + pub fn write(&mut self, write: bool) -> &mut OpenOptions { + self.0.write(write); + self + } + + /// See the underlying [`append`] call for details. + /// + /// [`append`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.append + pub fn append(&mut self, append: bool) -> &mut OpenOptions { + self.0.append(append); + self + } + + /// See the underlying [`truncate`] call for details. + /// + /// [`truncate`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.truncate + pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { + self.0.truncate(truncate); + self + } + + /// See the underlying [`create`] call for details. + /// + /// [`create`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create + pub fn create(&mut self, create: bool) -> &mut OpenOptions { + self.0.create(create); + self + } + + /// See the underlying [`create_new`] call for details. + /// + /// [`create_new`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.create_new + pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions { + self.0.create_new(create_new); + self + } + + /// Opens a file at `path` with the options specified by `self`. + /// + /// # Errors + /// + /// `OpenOptionsFuture` results in an error if called from outside of the + /// Tokio runtime or if the underlying [`open`] call results in an error. + /// + /// [`open`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open + pub fn open<P>(&self, path: P) -> OpenFuture<P> + where P: AsRef<Path> + Send + 'static + { + OpenFuture::new(self.0.clone(), path) + } +} + +impl From<StdOpenOptions> for OpenOptions { + fn from(options: StdOpenOptions) -> OpenOptions { + OpenOptions(options) + } +} diff --git a/third_party/rust/tokio-fs/src/file/seek.rs b/third_party/rust/tokio-fs/src/file/seek.rs new file mode 100644 index 0000000000..0765d3db90 --- /dev/null +++ b/third_party/rust/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<File>, + 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<Self::Item, Self::Error> { + 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/third_party/rust/tokio-fs/src/hard_link.rs b/third_party/rust/tokio-fs/src/hard_link.rs new file mode 100644 index 0000000000..e8ea511520 --- /dev/null +++ b/third_party/rust/tokio-fs/src/hard_link.rs @@ -0,0 +1,54 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Creates a new hard link on the filesystem. +/// +/// The `dst` path will be a link pointing to the `src` path. Note that systems +/// often require these two paths to both be located on the same filesystem. +/// +/// This is an async version of [`std::fs::hard_link`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.hard_link.html +pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> HardLinkFuture<P, Q> { + HardLinkFuture::new(src, dst) +} + +/// Future returned by `hard_link`. +#[derive(Debug)] +pub struct HardLinkFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + src: P, + dst: Q, +} + +impl<P, Q> HardLinkFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + fn new(src: P, dst: Q) -> HardLinkFuture<P, Q> { + HardLinkFuture { + src: src, + dst: dst, + } + } +} + +impl<P, Q> Future for HardLinkFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::hard_link(&self.src, &self.dst) ) + } +} diff --git a/third_party/rust/tokio-fs/src/lib.rs b/third_party/rust/tokio-fs/src/lib.rs new file mode 100644 index 0000000000..2beec8c0c6 --- /dev/null +++ b/third_party/rust/tokio-fs/src/lib.rs @@ -0,0 +1,104 @@ +//! Asynchronous file and standard stream adaptation. +//! +//! This module contains utility methods and adapter types for input/output to +//! files or standard streams (`Stdin`, `Stdout`, `Stderr`), and +//! filesystem manipulation, for use within (and only within) a Tokio runtime. +//! +//! Tasks run by *worker* threads should not block, as this could delay +//! servicing reactor events. Portable filesystem operations are blocking, +//! however. This module offers adapters which use a [`blocking`] annotation +//! to inform the runtime that a blocking operation is required. When +//! necessary, this allows the runtime to convert the current thread from a +//! *worker* to a *backup* thread, where blocking is acceptable. +//! +//! ## Usage +//! +//! Where possible, users should prefer the provided asynchronous-specific +//! traits such as [`AsyncRead`], or methods returning a `Future` or `Poll` +//! type. Adaptions also extend to traits like `std::io::Read` where methods +//! return `std::io::Result`. Be warned that these adapted methods may return +//! `std::io::ErrorKind::WouldBlock` if a *worker* thread can not be converted +//! to a *backup* thread immediately. See [tokio-threadpool] for more details +//! of the threading model and [`blocking`]. +//! +//! [`blocking`]: https://docs.rs/tokio-threadpool/0.1/tokio_threadpool/fn.blocking.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 + +#![deny(missing_docs, missing_debug_implementations, warnings)] +#![doc(html_root_url = "https://docs.rs/tokio-fs/0.1.3")] + +#[macro_use] +extern crate futures; +extern crate tokio_io; +extern crate tokio_threadpool; + +mod create_dir; +mod create_dir_all; +pub mod file; +mod hard_link; +mod metadata; +pub mod os; +mod read_dir; +mod read_link; +mod remove_dir; +mod remove_file; +mod rename; +mod set_permissions; +mod stdin; +mod stdout; +mod stderr; +mod symlink_metadata; + +pub use create_dir::{create_dir, CreateDirFuture}; +pub use create_dir_all::{create_dir_all, CreateDirAllFuture}; +pub use file::File; +pub use file::OpenOptions; +pub use hard_link::{hard_link, HardLinkFuture}; +pub use metadata::{metadata, MetadataFuture}; +pub use read_dir::{read_dir, ReadDirFuture, ReadDir, DirEntry}; +pub use read_link::{read_link, ReadLinkFuture}; +pub use remove_dir::{remove_dir, RemoveDirFuture}; +pub use remove_file::{remove_file, RemoveFileFuture}; +pub use rename::{rename, RenameFuture}; +pub use set_permissions::{set_permissions, SetPermissionsFuture}; +pub use stdin::{stdin, Stdin}; +pub use stdout::{stdout, Stdout}; +pub use stderr::{stderr, Stderr}; +pub use symlink_metadata::{symlink_metadata, SymlinkMetadataFuture}; + +use futures::Poll; +use futures::Async::*; + +use std::io; +use std::io::ErrorKind::{Other, WouldBlock}; + +fn blocking_io<F, T>(f: F) -> Poll<T, io::Error> +where F: FnOnce() -> io::Result<T>, +{ + match tokio_threadpool::blocking(f) { + Ok(Ready(Ok(v))) => Ok(v.into()), + Ok(Ready(Err(err))) => Err(err), + Ok(NotReady) => Ok(NotReady), + Err(_) => Err(blocking_err()), + } +} + +fn would_block<F, T>(f: F) -> io::Result<T> +where F: FnOnce() -> io::Result<T>, +{ + match tokio_threadpool::blocking(f) { + Ok(Ready(Ok(v))) => Ok(v), + Ok(Ready(Err(err))) => { + debug_assert_ne!(err.kind(), WouldBlock); + Err(err) + } + Ok(NotReady) => Err(WouldBlock.into()), + Err(_) => Err(blocking_err()), + } +} + +fn blocking_err() -> io::Error { + io::Error::new(Other, "`blocking` annotated I/O must be called \ + from the context of the Tokio runtime.") +} diff --git a/third_party/rust/tokio-fs/src/metadata.rs b/third_party/rust/tokio-fs/src/metadata.rs new file mode 100644 index 0000000000..200d58e080 --- /dev/null +++ b/third_party/rust/tokio-fs/src/metadata.rs @@ -0,0 +1,45 @@ +use super::blocking_io; + +use futures::{Future, Poll}; + +use std::fs::{self, Metadata}; +use std::io; +use std::path::Path; + +/// Queries the file system metadata for a path. +pub fn metadata<P>(path: P) -> MetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + MetadataFuture::new(path) +} + +/// Future returned by `metadata`. +#[derive(Debug)] +pub struct MetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + path: P, +} + +impl<P> MetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + pub(crate) fn new(path: P) -> Self { + Self { path } + } +} + +impl<P> Future for MetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + type Item = Metadata; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + blocking_io(|| fs::metadata(&self.path)) + } +} diff --git a/third_party/rust/tokio-fs/src/os/mod.rs b/third_party/rust/tokio-fs/src/os/mod.rs new file mode 100644 index 0000000000..ae57c48476 --- /dev/null +++ b/third_party/rust/tokio-fs/src/os/mod.rs @@ -0,0 +1,6 @@ +//! OS-specific functionality. + +#[cfg(unix)] +pub mod unix; +#[cfg(windows)] +pub mod windows; diff --git a/third_party/rust/tokio-fs/src/os/unix.rs b/third_party/rust/tokio-fs/src/os/unix.rs new file mode 100644 index 0000000000..5f8eedeba3 --- /dev/null +++ b/third_party/rust/tokio-fs/src/os/unix.rs @@ -0,0 +1,55 @@ +//! Unix-specific extensions to primitives in the `tokio_fs` module. + +use std::io; +use std::path::Path; +use std::os::unix::fs; + +use futures::{Future, Poll}; + +/// Creates a new symbolic link on the filesystem. +/// +/// The `dst` path will be a symbolic link pointing to the `src` path. +/// +/// This is an async version of [`std::os::unix::fs::symlink`][std] +/// +/// [std]: https://doc.rust-lang.org/std/os/unix/fs/fn.symlink.html +pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> SymlinkFuture<P, Q> { + SymlinkFuture::new(src, dst) +} + +/// Future returned by `symlink`. +#[derive(Debug)] +pub struct SymlinkFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + src: P, + dst: Q, +} + +impl<P, Q> SymlinkFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + fn new(src: P, dst: Q) -> SymlinkFuture<P, Q> { + SymlinkFuture { + src: src, + dst: dst, + } + } +} + +impl<P, Q> Future for SymlinkFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::symlink(&self.src, &self.dst) ) + } +} diff --git a/third_party/rust/tokio-fs/src/os/windows/mod.rs b/third_party/rust/tokio-fs/src/os/windows/mod.rs new file mode 100644 index 0000000000..eaeed043eb --- /dev/null +++ b/third_party/rust/tokio-fs/src/os/windows/mod.rs @@ -0,0 +1,7 @@ +//! Windows-specific extensions for the primitives in the `tokio_fs` module. + +mod symlink_dir; +mod symlink_file; + +pub use self::symlink_dir::{symlink_dir, SymlinkDirFuture}; +pub use self::symlink_file::{symlink_file, SymlinkFileFuture}; diff --git a/third_party/rust/tokio-fs/src/os/windows/symlink_dir.rs b/third_party/rust/tokio-fs/src/os/windows/symlink_dir.rs new file mode 100644 index 0000000000..9806ff3a3f --- /dev/null +++ b/third_party/rust/tokio-fs/src/os/windows/symlink_dir.rs @@ -0,0 +1,54 @@ +use std::io; +use std::path::Path; +use std::os::windows::fs; + +use futures::{Future, Poll}; + +/// Creates a new directory symlink on the filesystem. +/// +/// The `dst` path will be a directory symbolic link pointing to the `src` +/// path. +/// +/// This is an async version of [`std::os::windows::fs::symlink_dir`][std] +/// +/// [std]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_dir.html +pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> SymlinkDirFuture<P, Q> { + SymlinkDirFuture::new(src, dst) +} + +/// Future returned by `symlink_dir`. +#[derive(Debug)] +pub struct SymlinkDirFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + src: P, + dst: Q, +} + +impl<P, Q> SymlinkDirFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + fn new(src: P, dst: Q) -> SymlinkDirFuture<P, Q> { + SymlinkDirFuture { + src: src, + dst: dst, + } + } +} + +impl<P, Q> Future for SymlinkDirFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::symlink_dir(&self.src, &self.dst) ) + } +} diff --git a/third_party/rust/tokio-fs/src/os/windows/symlink_file.rs b/third_party/rust/tokio-fs/src/os/windows/symlink_file.rs new file mode 100644 index 0000000000..583b615874 --- /dev/null +++ b/third_party/rust/tokio-fs/src/os/windows/symlink_file.rs @@ -0,0 +1,54 @@ +use std::io; +use std::path::Path; +use std::os::windows::fs; + +use futures::{Future, Poll}; + +/// Creates a new file symbolic link on the filesystem. +/// +/// The `dst` path will be a file symbolic link pointing to the `src` +/// path. +/// +/// This is an async version of [`std::os::windows::fs::symlink_file`][std] +/// +/// [std]: https://doc.rust-lang.org/std/os/windows/fs/fn.symlink_file.html +pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> SymlinkFileFuture<P, Q> { + SymlinkFileFuture::new(src, dst) +} + +/// Future returned by `symlink_file`. +#[derive(Debug)] +pub struct SymlinkFileFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + src: P, + dst: Q, +} + +impl<P, Q> SymlinkFileFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + fn new(src: P, dst: Q) -> SymlinkFileFuture<P, Q> { + SymlinkFileFuture { + src: src, + dst: dst, + } + } +} + +impl<P, Q> Future for SymlinkFileFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::symlink_file(&self.src, &self.dst) ) + } +} diff --git a/third_party/rust/tokio-fs/src/read_dir.rs b/third_party/rust/tokio-fs/src/read_dir.rs new file mode 100644 index 0000000000..3818c7102b --- /dev/null +++ b/third_party/rust/tokio-fs/src/read_dir.rs @@ -0,0 +1,247 @@ +use std::ffi::OsString; +use std::fs::{self, DirEntry as StdDirEntry, ReadDir as StdReadDir, FileType, Metadata}; +use std::io; +#[cfg(unix)] +use std::os::unix::fs::DirEntryExt; +use std::path::{Path, PathBuf}; + +use futures::{Future, Poll, Stream}; + +/// Returns a stream over the entries within a directory. +/// +/// This is an async version of [`std::fs::read_dir`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.read_dir.html +pub fn read_dir<P>(path: P) -> ReadDirFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + ReadDirFuture::new(path) +} + +/// Future returned by `read_dir`. +#[derive(Debug)] +pub struct ReadDirFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + path: P, +} + +impl<P> ReadDirFuture<P> +where + P: AsRef<Path> + Send + 'static +{ + fn new(path: P) -> ReadDirFuture<P> { + ReadDirFuture { + path: path, + } + } +} + +impl<P> Future for ReadDirFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + type Item = ReadDir; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, io::Error> { + ::blocking_io(|| Ok(ReadDir(fs::read_dir(&self.path)?))) + } +} + +/// Stream of the entries in a directory. +/// +/// This stream is returned from the [`read_dir`] function of this module and +/// will yield instances of [`DirEntry`]. Through a [`DirEntry`] +/// information like the entry's path and possibly other metadata can be +/// learned. +/// +/// # Errors +/// +/// This [`Stream`] will return an [`Err`] if there's some sort of intermittent +/// IO error during iteration. +/// +/// [`read_dir`]: fn.read_dir.html +/// [`DirEntry`]: struct.DirEntry.html +/// [`Stream`]: ../futures/stream/trait.Stream.html +/// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err +#[derive(Debug)] +pub struct ReadDir(StdReadDir); + +impl Stream for ReadDir { + type Item = DirEntry; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { + ::blocking_io(|| { + match self.0.next() { + Some(Err(err)) => Err(err), + Some(Ok(item)) => Ok(Some(DirEntry(item))), + None => Ok(None) + } + }) + } +} + +/// Entries returned by the [`ReadDir`] stream. +/// +/// [`ReadDir`]: struct.ReadDir.html +/// +/// This is a specialized version of [`std::fs::DirEntry`][std] for usage from the +/// Tokio runtime. +/// +/// An instance of `DirEntry` represents an entry inside of a directory on the +/// filesystem. Each entry can be inspected via methods to learn about the full +/// path or possibly other metadata through per-platform extension traits. +/// +/// [std]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html +#[derive(Debug)] +pub struct DirEntry(StdDirEntry); + +impl DirEntry { + /// Destructures the `tokio_fs::DirEntry` into a [`std::fs::DirEntry`][std]. + /// + /// [std]: https://doc.rust-lang.org/std/fs/struct.DirEntry.html + pub fn into_std(self) -> StdDirEntry { + self.0 + } + + /// Returns the full path to the file that this entry represents. + /// + /// The full path is created by joining the original path to `read_dir` + /// with the filename of this entry. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate tokio; + /// # extern crate tokio_fs; + /// use futures::{Future, Stream}; + /// + /// fn main() { + /// let fut = tokio_fs::read_dir(".").flatten_stream().for_each(|dir| { + /// println!("{:?}", dir.path()); + /// Ok(()) + /// }).map_err(|err| { eprintln!("Error: {:?}", err); () }); + /// tokio::run(fut); + /// } + /// ``` + /// + /// This prints output like: + /// + /// ```text + /// "./whatever.txt" + /// "./foo.html" + /// "./hello_world.rs" + /// ``` + /// + /// The exact text, of course, depends on what files you have in `.`. + pub fn path(&self) -> PathBuf { + self.0.path() + } + + /// Returns the bare file name of this directory entry without any other + /// leading path component. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate tokio; + /// # extern crate tokio_fs; + /// use futures::{Future, Stream}; + /// + /// fn main() { + /// let fut = tokio_fs::read_dir(".").flatten_stream().for_each(|dir| { + /// // Here, `dir` is a `DirEntry`. + /// println!("{:?}", dir.file_name()); + /// Ok(()) + /// }).map_err(|err| { eprintln!("Error: {:?}", err); () }); + /// tokio::run(fut); + /// } + /// ``` + pub fn file_name(&self) -> OsString { + self.0.file_name() + } + + /// Return the metadata for the file that this entry points at. + /// + /// This function will not traverse symlinks if this entry points at a + /// symlink. + /// + /// # Platform-specific behavior + /// + /// On Windows this function is cheap to call (no extra system calls + /// needed), but on Unix platforms this function is the equivalent of + /// calling `symlink_metadata` on the path. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate tokio; + /// # extern crate tokio_fs; + /// use futures::{Future, Stream}; + /// use futures::future::poll_fn; + /// + /// fn main() { + /// let fut = tokio_fs::read_dir(".").flatten_stream().for_each(|dir| { + /// // Here, `dir` is a `DirEntry`. + /// let path = dir.path(); + /// poll_fn(move || dir.poll_metadata()).map(move |metadata| { + /// println!("{:?}: {:?}", path, metadata.permissions()); + /// }) + /// }).map_err(|err| { eprintln!("Error: {:?}", err); () }); + /// tokio::run(fut); + /// } + /// ``` + pub fn poll_metadata(&self) -> Poll<Metadata, io::Error> { + ::blocking_io(|| self.0.metadata()) + } + + /// Return the file type for the file that this entry points at. + /// + /// This function will not traverse symlinks if this entry points at a + /// symlink. + /// + /// # Platform-specific behavior + /// + /// On Windows and most Unix platforms this function is free (no extra + /// system calls needed), but some Unix platforms may require the equivalent + /// call to `symlink_metadata` to learn about the target file type. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate tokio; + /// # extern crate tokio_fs; + /// use futures::{Future, Stream}; + /// use futures::future::poll_fn; + /// + /// fn main() { + /// let fut = tokio_fs::read_dir(".").flatten_stream().for_each(|dir| { + /// // Here, `dir` is a `DirEntry`. + /// let path = dir.path(); + /// poll_fn(move || dir.poll_file_type()).map(move |file_type| { + /// // Now let's show our entry's file type! + /// println!("{:?}: {:?}", path, file_type); + /// }) + /// }).map_err(|err| { eprintln!("Error: {:?}", err); () }); + /// tokio::run(fut); + /// } + /// ``` + pub fn poll_file_type(&self) -> Poll<FileType, io::Error> { + ::blocking_io(|| self.0.file_type()) + } +} + +#[cfg(unix)] +impl DirEntryExt for DirEntry { + fn ino(&self) -> u64 { + self.0.ino() + } +} diff --git a/third_party/rust/tokio-fs/src/read_link.rs b/third_party/rust/tokio-fs/src/read_link.rs new file mode 100644 index 0000000000..5e5bf2a30e --- /dev/null +++ b/third_party/rust/tokio-fs/src/read_link.rs @@ -0,0 +1,46 @@ +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +use futures::{Future, Poll}; + +/// Reads a symbolic link, returning the file that the link points to. +/// +/// This is an async version of [`std::fs::read_link`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.read_link.html +pub fn read_link<P: AsRef<Path>>(path: P) -> ReadLinkFuture<P> { + ReadLinkFuture::new(path) +} + +/// Future returned by `read_link`. +#[derive(Debug)] +pub struct ReadLinkFuture<P> +where + P: AsRef<Path> +{ + path: P, +} + +impl<P> ReadLinkFuture<P> +where + P: AsRef<Path> +{ + fn new(path: P) -> ReadLinkFuture<P> { + ReadLinkFuture { + path: path, + } + } +} + +impl<P> Future for ReadLinkFuture<P> +where + P: AsRef<Path> +{ + type Item = PathBuf; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::read_link(&self.path) ) + } +} diff --git a/third_party/rust/tokio-fs/src/remove_dir.rs b/third_party/rust/tokio-fs/src/remove_dir.rs new file mode 100644 index 0000000000..5aa73bfb5f --- /dev/null +++ b/third_party/rust/tokio-fs/src/remove_dir.rs @@ -0,0 +1,46 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Removes an existing, empty directory. +/// +/// This is an async version of [`std::fs::remove_dir`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.remove_dir.html +pub fn remove_dir<P: AsRef<Path>>(path: P) -> RemoveDirFuture<P> { + RemoveDirFuture::new(path) +} + +/// Future returned by `remove_dir`. +#[derive(Debug)] +pub struct RemoveDirFuture<P> +where + P: AsRef<Path> +{ + path: P, +} + +impl<P> RemoveDirFuture<P> +where + P: AsRef<Path> +{ + fn new(path: P) -> RemoveDirFuture<P> { + RemoveDirFuture { + path: path, + } + } +} + +impl<P> Future for RemoveDirFuture<P> +where + P: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::remove_dir(&self.path) ) + } +} diff --git a/third_party/rust/tokio-fs/src/remove_file.rs b/third_party/rust/tokio-fs/src/remove_file.rs new file mode 100644 index 0000000000..f617418579 --- /dev/null +++ b/third_party/rust/tokio-fs/src/remove_file.rs @@ -0,0 +1,50 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Removes a file from the filesystem. +/// +/// Note that there is no +/// guarantee that the file is immediately deleted (e.g. depending on +/// platform, other open file descriptors may prevent immediate removal). +/// +/// This is an async version of [`std::fs::remove_file`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.remove_file.html +pub fn remove_file<P: AsRef<Path>>(path: P) -> RemoveFileFuture<P> { + RemoveFileFuture::new(path) +} + +/// Future returned by `remove_file`. +#[derive(Debug)] +pub struct RemoveFileFuture<P> +where + P: AsRef<Path> +{ + path: P, +} + +impl<P> RemoveFileFuture<P> +where + P: AsRef<Path> +{ + fn new(path: P) -> RemoveFileFuture<P> { + RemoveFileFuture { + path: path, + } + } +} + +impl<P> Future for RemoveFileFuture<P> +where + P: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::remove_file(&self.path) ) + } +} diff --git a/third_party/rust/tokio-fs/src/rename.rs b/third_party/rust/tokio-fs/src/rename.rs new file mode 100644 index 0000000000..210f53bb5a --- /dev/null +++ b/third_party/rust/tokio-fs/src/rename.rs @@ -0,0 +1,54 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Rename a file or directory to a new name, replacing the original file if +/// `to` already exists. +/// +/// This will not work if the new name is on a different mount point. +/// +/// This is an async version of [`std::fs::rename`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.rename.html +pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> RenameFuture<P, Q> { + RenameFuture::new(from, to) +} + +/// Future returned by `rename`. +#[derive(Debug)] +pub struct RenameFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + from: P, + to: Q, +} + +impl<P, Q> RenameFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + fn new(from: P, to: Q) -> RenameFuture<P, Q> { + RenameFuture { + from: from, + to: to, + } + } +} + +impl<P, Q> Future for RenameFuture<P, Q> +where + P: AsRef<Path>, + Q: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::rename(&self.from, &self.to) ) + } +} diff --git a/third_party/rust/tokio-fs/src/set_permissions.rs b/third_party/rust/tokio-fs/src/set_permissions.rs new file mode 100644 index 0000000000..a850448626 --- /dev/null +++ b/third_party/rust/tokio-fs/src/set_permissions.rs @@ -0,0 +1,48 @@ +use std::fs; +use std::io; +use std::path::Path; + +use futures::{Future, Poll}; + +/// Changes the permissions found on a file or a directory. +/// +/// This is an async version of [`std::fs::set_permissions`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.set_permissions.html +pub fn set_permissions<P: AsRef<Path>>(path: P, perm: fs::Permissions) -> SetPermissionsFuture<P> { + SetPermissionsFuture::new(path, perm) +} + +/// Future returned by `set_permissions`. +#[derive(Debug)] +pub struct SetPermissionsFuture<P> +where + P: AsRef<Path> +{ + path: P, + perm: fs::Permissions, +} + +impl<P> SetPermissionsFuture<P> +where + P: AsRef<Path> +{ + fn new(path: P, perm: fs::Permissions) -> SetPermissionsFuture<P> { + SetPermissionsFuture { + path: path, + perm: perm, + } + } +} + +impl<P> Future for SetPermissionsFuture<P> +where + P: AsRef<Path> +{ + type Item = (); + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + ::blocking_io(|| fs::set_permissions(&self.path, self.perm.clone()) ) + } +} diff --git a/third_party/rust/tokio-fs/src/stderr.rs b/third_party/rust/tokio-fs/src/stderr.rs new file mode 100644 index 0000000000..cf64390757 --- /dev/null +++ b/third_party/rust/tokio-fs/src/stderr.rs @@ -0,0 +1,45 @@ +use tokio_io::{AsyncWrite}; + +use futures::Poll; + +use std::io::{self, Write, Stderr as StdStderr}; + +/// A handle to the standard error stream of a process. +/// +/// The handle implements the [`AsyncWrite`] trait, but beware that concurrent +/// writes to `Stderr` must be executed with care. +/// +/// Created by the [`stderr`] function. +/// +/// [`stderr`]: fn.stderr.html +/// [`AsyncWrite`]: trait.AsyncWrite.html +#[derive(Debug)] +pub struct Stderr { + std: StdStderr, +} + +/// Constructs a new handle to the standard error of the current process. +/// +/// The returned handle allows writing to standard error from the within the +/// Tokio runtime. +pub fn stderr() -> Stderr { + let std = io::stderr(); + Stderr { std } +} + +impl Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + ::would_block(|| self.std.write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + ::would_block(|| self.std.flush()) + } +} + +impl AsyncWrite for Stderr { + fn shutdown(&mut self) -> Poll<(), io::Error> { + Ok(().into()) + } +} + diff --git a/third_party/rust/tokio-fs/src/stdin.rs b/third_party/rust/tokio-fs/src/stdin.rs new file mode 100644 index 0000000000..f41b8dc84c --- /dev/null +++ b/third_party/rust/tokio-fs/src/stdin.rs @@ -0,0 +1,38 @@ +use tokio_io::{AsyncRead}; + +use std::io::{self, Read, Stdin as StdStdin}; + +/// A handle to the standard input stream of a process. +/// +/// The handle implements the [`AsyncRead`] trait, but beware that concurrent +/// reads of `Stdin` must be executed with care. +/// +/// Created by the [`stdin`] function. +/// +/// [`stdin`]: fn.stdin.html +/// [`AsyncRead`]: trait.AsyncRead.html +#[derive(Debug)] +pub struct Stdin { + std: StdStdin, +} + +/// Constructs a new handle to the standard input of the current process. +/// +/// The returned handle allows reading from standard input from the within the +/// Tokio runtime. +pub fn stdin() -> Stdin { + let std = io::stdin(); + Stdin { std } +} + +impl Read for Stdin { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + ::would_block(|| self.std.read(buf)) + } +} + +impl AsyncRead for Stdin { + unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { + false + } +} diff --git a/third_party/rust/tokio-fs/src/stdout.rs b/third_party/rust/tokio-fs/src/stdout.rs new file mode 100644 index 0000000000..1c4cd5ad05 --- /dev/null +++ b/third_party/rust/tokio-fs/src/stdout.rs @@ -0,0 +1,44 @@ +use tokio_io::{AsyncWrite}; + +use futures::Poll; + +use std::io::{self, Write, Stdout as StdStdout}; + +/// A handle to the standard output stream of a process. +/// +/// The handle implements the [`AsyncWrite`] trait, but beware that concurrent +/// writes to `Stdout` must be executed with care. +/// +/// Created by the [`stdout`] function. +/// +/// [`stdout`]: fn.stdout.html +/// [`AsyncWrite`]: trait.AsyncWrite.html +#[derive(Debug)] +pub struct Stdout { + std: StdStdout, +} + +/// Constructs a new handle to the standard output of the current process. +/// +/// The returned handle allows writing to standard out from the within the Tokio +/// runtime. +pub fn stdout() -> Stdout { + let std = io::stdout(); + Stdout { std } +} + +impl Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + ::would_block(|| self.std.write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + ::would_block(|| self.std.flush()) + } +} + +impl AsyncWrite for Stdout { + fn shutdown(&mut self) -> Poll<(), io::Error> { + Ok(().into()) + } +} diff --git a/third_party/rust/tokio-fs/src/symlink_metadata.rs b/third_party/rust/tokio-fs/src/symlink_metadata.rs new file mode 100644 index 0000000000..db02769e20 --- /dev/null +++ b/third_party/rust/tokio-fs/src/symlink_metadata.rs @@ -0,0 +1,49 @@ +use super::blocking_io; + +use futures::{Future, Poll}; + +use std::fs::{self, Metadata}; +use std::io; +use std::path::Path; + +/// Queries the file system metadata for a path. +/// +/// This is an async version of [`std::fs::symlink_metadata`][std] +/// +/// [std]: https://doc.rust-lang.org/std/fs/fn.symlink_metadata.html +pub fn symlink_metadata<P>(path: P) -> SymlinkMetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + SymlinkMetadataFuture::new(path) +} + +/// Future returned by `symlink_metadata`. +#[derive(Debug)] +pub struct SymlinkMetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + path: P, +} + +impl<P> SymlinkMetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + pub(crate) fn new(path: P) -> Self { + Self { path } + } +} + +impl<P> Future for SymlinkMetadataFuture<P> +where + P: AsRef<Path> + Send + 'static, +{ + type Item = Metadata; + type Error = io::Error; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + blocking_io(|| fs::symlink_metadata(&self.path)) + } +} diff --git a/third_party/rust/tokio-fs/tests/file.rs b/third_party/rust/tokio-fs/tests/file.rs new file mode 100644 index 0000000000..c8185c1f22 --- /dev/null +++ b/third_party/rust/tokio-fs/tests/file.rs @@ -0,0 +1,146 @@ +extern crate futures; +extern crate rand; +extern crate tempdir; +extern crate tokio_fs; +extern crate tokio_io; +extern crate tokio_threadpool; + +use tokio_fs::*; +use tokio_io::io; +use tokio_threadpool::*; + +use futures::Future; +use futures::future::poll_fn; +use futures::sync::oneshot; +use rand::{thread_rng, Rng}; +use tempdir::TempDir; + +use std::fs::File as StdFile; +use std::io::{Read, SeekFrom}; + +#[test] +fn read_write() { + const NUM_CHARS: usize = 16 * 1_024; + + let dir = TempDir::new("tokio-fs-tests").unwrap(); + let file_path = dir.path().join("read_write.txt"); + + let contents: Vec<u8> = thread_rng().gen_ascii_chars() + .take(NUM_CHARS) + .collect::<String>() + .into(); + + let pool = Builder::new() + .pool_size(1) + .build(); + + let (tx, rx) = oneshot::channel(); + + pool.spawn({ + let file_path = file_path.clone(); + let contents = contents.clone(); + + File::create(file_path) + .and_then(|file| file.metadata()) + .inspect(|&(_, ref metadata)| assert!(metadata.is_file())) + .and_then(move |(file, _)| io::write_all(file, contents)) + .and_then(|(mut file, _)| { + poll_fn(move || file.poll_sync_all()) + }) + .then(|res| { + let _ = res.unwrap(); + tx.send(()).unwrap(); + Ok(()) + }) + }); + + rx.wait().unwrap(); + + let mut file = StdFile::open(&file_path).unwrap(); + + let mut dst = vec![]; + file.read_to_end(&mut dst).unwrap(); + + assert_eq!(dst, contents); + + let (tx, rx) = oneshot::channel(); + + pool.spawn({ + File::open(file_path) + .and_then(|file| io::read_to_end(file, vec![])) + .then(move |res| { + let (_, buf) = res.unwrap(); + assert_eq!(buf, contents); + tx.send(()).unwrap(); + Ok(()) + }) + }); + + rx.wait().unwrap(); +} + +#[test] +fn metadata() { + let dir = TempDir::new("tokio-fs-tests").unwrap(); + let file_path = dir.path().join("metadata.txt"); + + let pool = Builder::new().pool_size(1).build(); + + let (tx, rx) = oneshot::channel(); + + pool.spawn({ + let file_path = file_path.clone(); + let file_path2 = file_path.clone(); + let file_path3 = file_path.clone(); + + tokio_fs::metadata(file_path) + .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()); + tx.send(()) + }) + }); + + 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(); +} |