Enable API documentation for `std::os::wasi`.

This adds API documentation support for `std::os::wasi` modeled after
how `std::os::unix` works, so that WASI can be documented [here] along
with the other platforms.

[here]: https://doc.rust-lang.org/stable/std/os/index.html

Two changes of particular interest:

 - This changes the `AsRawFd` for `io::Stdin` for WASI to return
   `libc::STDIN_FILENO` instead of `sys::stdio::Stdin.as_raw_fd()` (and
   similar for `Stdout` and `Stderr`), which matches how the `unix`
   version works. `STDIN_FILENO` etc. may not always be explicitly
   reserved at the WASI level, but as long as we have Rust's `std` and
   `libc`, I think it's reasonable to guarantee that we'll always use
   `libc::STDIN_FILENO` for stdin.

 - This duplicates the `osstr2str` utility function, rather than
   trying to share it across all the configurations that need it.
This commit is contained in:
Dan Gohman 2021-02-22 14:21:43 -08:00
parent 446d4533e8
commit 132ec261b0
5 changed files with 79 additions and 19 deletions

View File

@ -22,6 +22,9 @@ pub use crate::sys::windows_ext as windows;
#[doc(cfg(target_os = "linux"))]
pub mod linux;
#[cfg(doc)]
pub use crate::sys::wasi_ext as wasi;
// If we're not documenting libstd then we just expose the main modules as we otherwise would.
#[cfg(not(doc))]

View File

@ -61,9 +61,9 @@ cfg_if::cfg_if! {
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as unix_ext;
} else if #[cfg(any(target_os = "hermit",
target_arch = "wasm32",
all(target_arch = "wasm32", not(target_os = "wasi")),
all(target_vendor = "fortanix", target_env = "sgx")))] {
// On wasm right now the module below doesn't compile
// On non-WASI wasm right now the module below doesn't compile
// (missing things in `libc` which is empty) so just omit everything
// with an empty module
#[unstable(issue = "none", feature = "std_internals")]
@ -85,9 +85,9 @@ cfg_if::cfg_if! {
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as windows_ext;
} else if #[cfg(any(target_os = "hermit",
target_arch = "wasm32",
all(target_arch = "wasm32", not(target_os = "wasi")),
all(target_vendor = "fortanix", target_env = "sgx")))] {
// On wasm right now the shim below doesn't compile, so
// On non-WASI wasm right now the shim below doesn't compile, so
// just omit it
#[unstable(issue = "none", feature = "std_internals")]
#[allow(missing_docs)]
@ -106,3 +106,25 @@ cfg_if::cfg_if! {
pub mod windows_ext;
}
}
#[cfg(doc)]
cfg_if::cfg_if! {
if #[cfg(target_os = "wasi")] {
// On WASI we'll document what's already available
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as wasi_ext;
} else if #[cfg(any(target_os = "hermit",
target_arch = "wasm32",
all(target_vendor = "fortanix", target_env = "sgx")))] {
// On non-WASI wasm right now the module below doesn't compile
// (missing things in `libc` which is empty) so just omit everything
// with an empty module
#[unstable(issue = "none", feature = "std_internals")]
#[allow(missing_docs)]
pub mod wasi_ext {}
} else {
// On other platforms like Windows document the bare bones of WASI
#[path = "wasi/ext/mod.rs"]
pub mod wasi_ext;
}
}

View File

@ -3,11 +3,14 @@
#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "wasi_ext", issue = "none")]
use crate::ffi::OsStr;
use crate::fs::{self, File, Metadata, OpenOptions};
use crate::io::{self, IoSlice, IoSliceMut};
use crate::path::{Path, PathBuf};
use crate::sys::fs::osstr2str;
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
// Used for `File::read` on intra-doc links
#[allow(unused_imports)]
use io::{Read, Write};
/// WASI-specific extensions to [`File`].
pub trait FileExt {
@ -54,11 +57,11 @@ pub trait FileExt {
/// # Errors
///
/// If this function encounters an error of the kind
/// [`ErrorKind::Interrupted`] then the error is ignored and the operation
/// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
/// will continue.
///
/// If this function encounters an "end of file" before completely filling
/// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
/// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
/// The contents of `buf` are unspecified in this case.
///
/// If any other read error is encountered then this function immediately
@ -131,16 +134,16 @@ pub trait FileExt {
/// The current file cursor is not affected by this function.
///
/// This method will continuously call [`write_at`] until there is no more data
/// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
/// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
/// returned. This method will not return until the entire buffer has been
/// successfully written or such an error occurs. The first error that is
/// not of [`ErrorKind::Interrupted`] kind generated from this method will be
/// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
/// returned.
///
/// # Errors
///
/// This function will return the first error of
/// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
/// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
///
/// [`write_at`]: FileExt::write_at
#[stable(feature = "rw_exact_all_at", since = "1.33.0")]
@ -426,7 +429,7 @@ impl MetadataExt for fs::Metadata {
}
}
/// WASI-specific extensions for [`FileType`].
/// WASI-specific extensions for [`fs::FileType`].
///
/// Adds support for special WASI file types such as block/character devices,
/// pipes, and sockets.
@ -517,8 +520,12 @@ pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
/// Create a symbolic link.
///
/// This is a convenience API similar to [`std::os::unix::fs::symlink`] and
/// [`std::os::windows::fs::symlink_file`] and [`symlink_dir`](std::os::windows::fs::symlink_dir).
/// This is a convenience API similar to `std::os::unix::fs::symlink` and
/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
}
fn osstr2str(f: &OsStr) -> io::Result<&str> {
f.to_str().ok_or_else(|| io::Error::new(io::ErrorKind::Other, "input must be utf-8"))
}

View File

@ -145,36 +145,36 @@ impl IntoRawFd for fs::File {
impl AsRawFd for io::Stdin {
fn as_raw_fd(&self) -> RawFd {
sys::stdio::Stdin.as_raw_fd()
libc::STDIN_FILENO
}
}
impl AsRawFd for io::Stdout {
fn as_raw_fd(&self) -> RawFd {
sys::stdio::Stdout.as_raw_fd()
libc::STDOUT_FILENO
}
}
impl AsRawFd for io::Stderr {
fn as_raw_fd(&self) -> RawFd {
sys::stdio::Stderr.as_raw_fd()
libc::STDERR_FILENO
}
}
impl<'a> AsRawFd for io::StdinLock<'a> {
fn as_raw_fd(&self) -> RawFd {
sys::stdio::Stdin.as_raw_fd()
libc::STDIN_FILENO
}
}
impl<'a> AsRawFd for io::StdoutLock<'a> {
fn as_raw_fd(&self) -> RawFd {
sys::stdio::Stdout.as_raw_fd()
libc::STDOUT_FILENO
}
}
impl<'a> AsRawFd for io::StderrLock<'a> {
fn as_raw_fd(&self) -> RawFd {
sys::stdio::Stderr.as_raw_fd()
libc::STDERR_FILENO
}
}

View File

@ -1,4 +1,32 @@
//! Platform-specific extensions to `std` for WASI.
//!
//! Provides access to platform-level information on WASI, and exposes
//! WASI-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings (`OsStr`,
//! `OsString`), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::wasi::prelude::*;
//!
//! fn main() -> std::io::Result<()> {
//! let f = File::create("foo.txt")?;
//! let fd = f.as_raw_fd();
//!
//! // use fd with native WASI bindings
//!
//! Ok(())
//! }
//! ```
#![deny(unsafe_op_in_unsafe_fn)]
#![doc(cfg(target_os = "wasi"))]
pub mod ffi;
pub mod fs;