diff options
Diffstat (limited to 'vendor/io-lifetimes/examples')
-rw-r--r-- | vendor/io-lifetimes/examples/easy-conversions.rs | 30 | ||||
-rw-r--r-- | vendor/io-lifetimes/examples/flexible-apis.rs | 108 | ||||
-rw-r--r-- | vendor/io-lifetimes/examples/hello.rs | 129 | ||||
-rw-r--r-- | vendor/io-lifetimes/examples/owning-wrapper.rs | 147 | ||||
-rw-r--r-- | vendor/io-lifetimes/examples/portable-views.rs | 28 |
5 files changed, 442 insertions, 0 deletions
diff --git a/vendor/io-lifetimes/examples/easy-conversions.rs b/vendor/io-lifetimes/examples/easy-conversions.rs new file mode 100644 index 000000000..87481c12f --- /dev/null +++ b/vendor/io-lifetimes/examples/easy-conversions.rs @@ -0,0 +1,30 @@ +//! io-lifetimes provides safe, portable, and convenient conversions from types +//! implementing `IntoFilelike` and `FromSocketlike` to types implementing +//! `FromFilelike` and `IntoSocketlike`, respectively. + +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +use io_lifetimes::FromFilelike; +use std::fs::File; +use std::io::{self, Read}; +use std::process::{Command, Stdio}; + +fn main() -> io::Result<()> { + let mut child = Command::new("cargo") + .arg("--help") + .stdout(Stdio::piped()) + .spawn() + .expect("failed to execute child"); + + // Convert from `ChildStderr` into `File` without any platform-specific + // code or `unsafe`! + let mut file = File::from_into_filelike(child.stdout.take().unwrap()); + + // Well, this example is not actually that cool, because `File` doesn't let + // you do anything that you couldn't already do with `ChildStderr` etc., but + // it's useful outside of standard library types. + let mut buffer = String::new(); + file.read_to_string(&mut buffer)?; + + Ok(()) +} diff --git a/vendor/io-lifetimes/examples/flexible-apis.rs b/vendor/io-lifetimes/examples/flexible-apis.rs new file mode 100644 index 000000000..8eb19a287 --- /dev/null +++ b/vendor/io-lifetimes/examples/flexible-apis.rs @@ -0,0 +1,108 @@ +//! io-lifetimes provides two different options for library authors +//! writing APIs which accept untyped I/O resources. +//! +//! The following uses the POSIX-ish `Fd` types; similar considerations +//! apply to the Windows and portable types. + +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +#[cfg(all(feature = "close", not(windows)))] +use io_lifetimes::{AsFd, BorrowedFd, IntoFd, OwnedFd}; + +/// The simplest way to accept a borrowed I/O resource is to simply use a +/// `BorrwedFd` as an argument. This doesn't require the function to have any +/// type parameters. It also works in FFI signatures, as `BorrowedFd` and (on +/// Rust nightly) `Option<BorrowedFd>` are guaranteed to have the same layout +/// as `RawFd`. +/// +/// Callers with an `AsFd`-implementing type would call `.as_fd()` and pass +/// the result. +#[cfg(all(feature = "close", not(windows)))] +fn use_fd_a(fd: BorrowedFd<'_>) { + let _ = fd; +} + +/// Another way to do this is to use an `AsFd` type parameter. This is more +/// verbose at the function definition site, and entails monomorphization, but +/// it has the advantage of allowing users to pass in any type implementing +/// `AsFd` directly, without having to call `.as_fd()` themselves. +#[cfg(all(feature = "close", not(windows)))] +fn use_fd_b<Fd: AsFd>(fd: Fd) { + let _ = fd.as_fd(); +} + +/// Another way to do this is to use an `impl AsFd` parameter. +#[cfg(all(feature = "close", not(windows)))] +fn use_fd_c(fd: impl AsFd) { + let _ = fd.as_fd(); +} + +/// The simplest way to accept a consumed I/O resource is to simply use an +/// `OwnedFd` as an argument. Similar to `use_fd_a`, this doesn't require the +/// function to have any type parameters, and also works in FFI signatures. +/// +/// Callers with an `IntoFd`-implementing type would call `.into_fd()` and pass +/// the result. +#[cfg(all(feature = "close", not(windows)))] +fn consume_fd_a(fd: OwnedFd) { + let _ = fd; +} + +/// Another way to do this is to use an `IntoFd` type parameter. Similar to +/// `use_fd_b`, this is more verbose here and entails monomorphization, but it +/// has the advantage of allowing users to pass in any type implementing +/// `IntoFd` directly. +#[cfg(all(feature = "close", not(windows)))] +fn consume_fd_b<Fd: IntoFd>(fd: Fd) { + let _ = fd.into_fd(); +} + +/// Another way to do this is to use an `impl IntoFd` parameter. +#[cfg(all(feature = "close", not(windows)))] +fn consume_fd_c(fd: impl IntoFd) { + let _ = fd.into_fd(); +} + +/// Now let's see how the APIs look for users. +#[cfg(all(feature = "close", not(windows)))] +fn main() { + let f = std::fs::File::open("Cargo.toml").unwrap(); + + // The simple option requires an `.as_fd()` at the callsite. + use_fd_a(f.as_fd()); + + // Another option can take a reference to any owning type directly. + use_fd_b(&f); + + // Of course, users can still pass in `BorrowedFd` values if they want to. + use_fd_b(f.as_fd()); + + // The other option is `impl AsFd`. + use_fd_c(&f); + + // Users can still pass in `BorrowedFd` values if they want to here too. + use_fd_c(f.as_fd()); + + let a = std::fs::File::open("Cargo.toml").unwrap(); + let b = std::fs::File::open("Cargo.toml").unwrap(); + let c = std::fs::File::open("Cargo.toml").unwrap(); + + // The simple option requires an `.into_fd()` at the callsite. + consume_fd_a(a.into_fd()); + + // Another option can take any `IntoFd` type directly. + consume_fd_b(b); + + // The other option can take any `IntoFd` type directly. + consume_fd_c(c); +} + +#[cfg(windows)] +fn main() { + println!("This example uses non-Windows APIs."); +} + +#[cfg(all(not(feature = "close"), not(windows)))] +fn main() { + println!("This example requires the \"close\" feature."); +} diff --git a/vendor/io-lifetimes/examples/hello.rs b/vendor/io-lifetimes/examples/hello.rs new file mode 100644 index 000000000..4f6b1a4ed --- /dev/null +++ b/vendor/io-lifetimes/examples/hello.rs @@ -0,0 +1,129 @@ +//! A simple testcase that prints a few messages to the console, demonstrating +//! the io-lifetimes API. + +#![cfg_attr(not(rustc_attrs), allow(unused_imports))] +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +#[cfg(feature = "close")] +use io_lifetimes::example_ffi::*; +#[cfg(feature = "close")] +use std::{ + fs::File, + io::{self, Write}, +}; + +#[cfg(all(unix, feature = "close"))] +use io_lifetimes::{AsFd, FromFd, OwnedFd}; + +#[cfg(windows)] +use io_lifetimes::{AsHandle, FromHandle, OwnedHandle}; +#[cfg(windows)] +use std::{convert::TryInto, os::windows::io::RawHandle, ptr::null_mut}; + +#[cfg(all(rustc_attrs, unix, feature = "close"))] +fn main() -> io::Result<()> { + let fd = unsafe { + // Open a file, which returns an `Option<OwnedFd>`, which we can + // maybe convert into an `OwnedFile`. + let fd: OwnedFd = open("/dev/stdout\0".as_ptr() as *const _, O_WRONLY | O_CLOEXEC) + .ok_or_else(io::Error::last_os_error)?; + + // Borrow the fd to write to it. + let result = write(fd.as_fd(), "hello, world\n".as_ptr() as *const _, 13); + match result { + -1 => return Err(io::Error::last_os_error()), + 13 => (), + _ => return Err(io::Error::new(io::ErrorKind::Other, "short write")), + } + + fd + }; + + // Convert into a `File`. No `unsafe` here! + let mut file = File::from_fd(fd); + writeln!(&mut file, "greetings, y'all")?; + + // We can borrow a `BorrowedFd` from a `File`. + unsafe { + let result = write(file.as_fd(), "sup?\n".as_ptr() as *const _, 5); + match result { + -1 => return Err(io::Error::last_os_error()), + 5 => (), + _ => return Err(io::Error::new(io::ErrorKind::Other, "short write")), + } + } + + // `OwnedFd` closes the fd in its `Drop` implementation. + + Ok(()) +} + +/// The Windows analog of the above. +#[cfg(all(windows, feature = "close"))] +fn main() -> io::Result<()> { + let handle = unsafe { + // Open a file, which returns an `HandleOrInvalid`, which we can fallibly + // convert into an `OwnedFile`. + let handle: OwnedHandle = CreateFileW( + ['C' as u16, 'O' as _, 'N' as _, 0].as_ptr(), + FILE_GENERIC_WRITE, + 0, + null_mut(), + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + null_mut() as RawHandle as HANDLE, + ) + .try_into() + .map_err(|_err| io::Error::last_os_error())?; + + // Borrow the handle to write to it. + let mut number_of_bytes_written = 0; + let result = WriteFile( + handle.as_handle(), + "hello, world\n".as_ptr() as *const _, + 13, + &mut number_of_bytes_written, + null_mut(), + ); + match (result, number_of_bytes_written) { + (0, _) => return Err(io::Error::last_os_error()), + (_, 13) => (), + (_, _) => return Err(io::Error::new(io::ErrorKind::Other, "short write")), + } + + handle + }; + + // Convert into a `File`. No `unsafe` here! + let mut file = File::from_handle(handle); + writeln!(&mut file, "greetings, y'all")?; + + // We can borrow a `BorrowedHandle` from a `File`. + unsafe { + let mut number_of_bytes_written = 0; + let result = WriteFile( + file.as_handle(), + "sup?\n".as_ptr() as *const _, + 5, + &mut number_of_bytes_written, + null_mut(), + ); + match (result, number_of_bytes_written) { + (0, _) => return Err(io::Error::last_os_error()), + (_, 5) => (), + (_, _) => return Err(io::Error::new(io::ErrorKind::Other, "short write")), + } + } + + // `OwnedHandle` closes the handle in its `Drop` implementation. + + Ok(()) +} + +#[cfg(all( + not(all(rustc_attrs, unix, feature = "close")), + not(all(windows, feature = "close")) +))] +fn main() { + println!("On Unix, this example requires Rust nightly (for `rustc_attrs`) and the \"close\" feature."); +} diff --git a/vendor/io-lifetimes/examples/owning-wrapper.rs b/vendor/io-lifetimes/examples/owning-wrapper.rs new file mode 100644 index 000000000..74a05b2f4 --- /dev/null +++ b/vendor/io-lifetimes/examples/owning-wrapper.rs @@ -0,0 +1,147 @@ +//! A simple example implementing the main traits for a type. + +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +use io_lifetimes::OwnedFilelike; +#[cfg(not(windows))] +use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd}; +#[cfg(windows)] +use io_lifetimes::{AsHandle, BorrowedHandle, FromHandle, IntoHandle, OwnedHandle}; + +/// A wrapper around a file descriptor. +/// +/// Implementing `AsFd`, `IntoFd`, and `FromFd` for a type that wraps an +/// `Owned*` is straightforward. `Owned*` types also automatically close the +/// handle in its `Drop`. +/// +/// Should owning wrappers implement `AsRawFd`, `IntoRawFd`, and `FromRawFd` +/// too? They can, and there's no need to remove them from a type that already +/// implements them. But for new code, they can be omitted. Users that really +/// need the raw value can always do `as_fd().as_raw_fd()`, +/// `.into_fd().into_raw_fd()`, or `T::from_fd(OwnedFd::from_raw_fd(raw_fd))`. +/// But if possible, users should use just `as_fd`, `into_fd`, and `from_fd` +/// and avoid working with raw values altogether. +struct Thing { + filelike: OwnedFilelike, +} + +#[cfg(not(windows))] +impl AsFd for Thing { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.filelike.as_fd() + } +} + +#[cfg(not(windows))] +impl IntoFd for Thing { + #[inline] + fn into_fd(self) -> OwnedFd { + self.filelike + } +} + +#[cfg(not(io_lifetimes_use_std))] +#[cfg(not(windows))] +impl From<Thing> for OwnedFd { + #[inline] + fn from(owned: Thing) -> Self { + owned.filelike + } +} + +#[cfg(not(windows))] +impl FromFd for Thing { + #[inline] + fn from_fd(filelike: OwnedFd) -> Self { + Self { filelike } + } +} + +#[cfg(not(io_lifetimes_use_std))] +#[cfg(not(windows))] +impl From<OwnedFd> for Thing { + #[inline] + fn from(filelike: OwnedFd) -> Self { + Self { filelike } + } +} + +#[cfg(windows)] +impl AsHandle for Thing { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + self.filelike.as_handle() + } +} + +#[cfg(windows)] +impl IntoHandle for Thing { + #[inline] + fn into_handle(self) -> OwnedHandle { + self.filelike + } +} + +#[cfg(not(io_lifetimes_use_std))] +#[cfg(windows)] +impl From<Thing> for OwnedHandle { + #[inline] + fn from(owned: Thing) -> Self { + owned.filelike + } +} + +#[cfg(windows)] +impl FromHandle for Thing { + #[inline] + fn from_handle(filelike: OwnedHandle) -> Self { + Self { filelike } + } +} + +#[cfg(not(io_lifetimes_use_std))] +#[cfg(windows)] +impl From<OwnedHandle> for Thing { + #[inline] + fn from(filelike: OwnedHandle) -> Self { + Self { filelike } + } +} + +#[cfg(feature = "close")] +fn main() { + use io_lifetimes::{AsFilelike, FromFilelike, IntoFilelike}; + + // Minimally exercise `Thing`'s Posix-ish API. + #[cfg(not(windows))] + { + let file = std::fs::File::open("Cargo.toml").unwrap(); + let thing = Thing::from_into_fd(file); + let _ = thing.as_fd(); + let _ = thing.into_fd(); + } + + // Minimally exercise `Thing`'s Windows API. + #[cfg(windows)] + { + let file = std::fs::File::open("Cargo.toml").unwrap(); + let thing = Thing::from_into_handle(file); + let _ = thing.as_handle(); + let _ = thing.into_handle(); + } + + // Implementing the above traits makes the blanket impls for the portable + // `Filelike` traits available too. + { + let file = std::fs::File::open("Cargo.toml").unwrap(); + let thing = Thing::from_into_filelike(file); + let _ = thing.as_filelike(); + let _ = thing.into_filelike(); + } +} + +#[cfg(not(feature = "close"))] +fn main() { + println!("This example requires the \"close\" feature."); +} diff --git a/vendor/io-lifetimes/examples/portable-views.rs b/vendor/io-lifetimes/examples/portable-views.rs new file mode 100644 index 000000000..410b4c2f0 --- /dev/null +++ b/vendor/io-lifetimes/examples/portable-views.rs @@ -0,0 +1,28 @@ +//! io-lifetimes provides safe, convenient, and portable ways to temporarily +//! view an I/O resource as a `File`, `Socket`, or other types. + +#![cfg_attr(io_lifetimes_use_std, feature(io_safety))] + +use io_lifetimes::AsFilelike; +use std::fs::File; +use std::io::{self, stdout}; + +fn main() -> io::Result<()> { + let stdout = stdout(); + + // With `AsFilelike`, any type implementing `AsFd`/`AsHandle` can be viewed + // as any type supporting `FromFilelike`, so you can call `File` methods on + // `Stdout` or other things. + // + // Whether or not you can actually do this is up to the OS, of course. In + // this case, Unix can do this, but it appears Windows can't. + let metadata = stdout.as_filelike_view::<File>().metadata()?; + + if metadata.is_file() { + println!("stdout is a file!"); + } else { + println!("stdout is not a file!"); + } + + Ok(()) +} |