diff options
Diffstat (limited to 'library/std/src/os/wasi')
-rw-r--r-- | library/std/src/os/wasi/ffi.rs | 11 | ||||
-rw-r--r-- | library/std/src/os/wasi/fs.rs | 558 | ||||
-rw-r--r-- | library/std/src/os/wasi/io/fd.rs | 9 | ||||
-rw-r--r-- | library/std/src/os/wasi/io/fd/tests.rs | 11 | ||||
-rw-r--r-- | library/std/src/os/wasi/io/mod.rs | 12 | ||||
-rw-r--r-- | library/std/src/os/wasi/io/raw.rs | 20 | ||||
-rw-r--r-- | library/std/src/os/wasi/mod.rs | 57 | ||||
-rw-r--r-- | library/std/src/os/wasi/net/mod.rs | 23 |
8 files changed, 701 insertions, 0 deletions
diff --git a/library/std/src/os/wasi/ffi.rs b/library/std/src/os/wasi/ffi.rs new file mode 100644 index 000000000..41dd8702e --- /dev/null +++ b/library/std/src/os/wasi/ffi.rs @@ -0,0 +1,11 @@ +//! WASI-specific extensions to primitives in the [`std::ffi`] module +//! +//! [`std::ffi`]: crate::ffi + +#![stable(feature = "rust1", since = "1.0.0")] + +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs new file mode 100644 index 000000000..160c8f1ec --- /dev/null +++ b/library/std/src/os/wasi/fs.rs @@ -0,0 +1,558 @@ +//! WASI-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "wasi_ext", issue = "71213")] + +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_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 { + /// Reads a number of bytes starting from a given offset. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Note that similar to [`File::read`], it is not an error to return with a + /// short read. + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + let bufs = &mut [IoSliceMut::new(buf)]; + self.read_vectored_at(bufs, offset) + } + + /// Reads a number of bytes starting from a given offset. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Note that similar to [`File::read_vectored`], it is not an error to + /// return with a short read. + fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>; + + /// Reads the exact number of byte required to fill `buf` from the given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. + /// + /// [`read_at`]: FileExt::read_at + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`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 [`io::ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + #[stable(feature = "rw_exact_all_at", since = "1.33.0")] + fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.read_at(buf, offset) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + offset += n as u64; + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")) + } else { + Ok(()) + } + } + + /// Writes a number of bytes starting from a given offset. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// When writing beyond the end of the file, the file is appropriately + /// extended and the intermediate bytes are initialized with the value 0. + /// + /// Note that similar to [`File::write`], it is not an error to return a + /// short write. + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + let bufs = &[IoSlice::new(buf)]; + self.write_vectored_at(bufs, offset) + } + + /// Writes a number of bytes starting from a given offset. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// When writing beyond the end of the file, the file is appropriately + /// extended and the intermediate bytes are initialized with the value 0. + /// + /// Note that similar to [`File::write_vectored`], it is not an error to return a + /// short write. + fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>; + + /// Attempts to write an entire buffer starting from a given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// 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-[`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 [`io::ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns. + /// + /// [`write_at`]: FileExt::write_at + #[stable(feature = "rw_exact_all_at", since = "1.33.0")] + fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.write_at(buf, offset) { + Ok(0) => { + return Err(io::const_io_error!( + io::ErrorKind::WriteZero, + "failed to write whole buffer", + )); + } + Ok(n) => { + buf = &buf[n..]; + offset += n as u64 + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Returns the current position within the file. + /// + /// This corresponds to the `fd_tell` syscall and is similar to + /// `seek` where you offset 0 bytes from the current position. + fn tell(&self) -> io::Result<u64>; + + /// Adjust the flags associated with this file. + /// + /// This corresponds to the `fd_fdstat_set_flags` syscall. + fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>; + + /// Adjust the rights associated with this file. + /// + /// This corresponds to the `fd_fdstat_set_rights` syscall. + fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>; + + /// Provide file advisory information on a file descriptor. + /// + /// This corresponds to the `fd_advise` syscall. + fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>; + + /// Force the allocation of space in a file. + /// + /// This corresponds to the `fd_allocate` syscall. + fn allocate(&self, offset: u64, len: u64) -> io::Result<()>; + + /// Create a directory. + /// + /// This corresponds to the `path_create_directory` syscall. + fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>; + + /// Read the contents of a symbolic link. + /// + /// This corresponds to the `path_readlink` syscall. + fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>; + + /// Return the attributes of a file or directory. + /// + /// This corresponds to the `path_filestat_get` syscall. + fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>; + + /// Unlink a file. + /// + /// This corresponds to the `path_unlink_file` syscall. + fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>; + + /// Remove a directory. + /// + /// This corresponds to the `path_remove_directory` syscall. + fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>; +} + +// FIXME: bind fd_fdstat_get - need to define a custom return type +// FIXME: bind fd_readdir - can't return `ReadDir` since we only have entry name +// FIXME: bind fd_filestat_set_times maybe? - on crates.io for unix +// FIXME: bind path_filestat_set_times maybe? - on crates.io for unix +// FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle +// FIXME: bind random_get maybe? - on crates.io for unix + +impl FileExt for fs::File { + fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + self.as_inner().as_inner().pread(bufs, offset) + } + + fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + self.as_inner().as_inner().pwrite(bufs, offset) + } + + fn tell(&self) -> io::Result<u64> { + self.as_inner().as_inner().tell() + } + + fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { + self.as_inner().as_inner().set_flags(flags) + } + + fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> { + self.as_inner().as_inner().set_rights(rights, inheriting) + } + + fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { + let advice = match advice { + a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL, + a if a == wasi::ADVICE_SEQUENTIAL.raw() => wasi::ADVICE_SEQUENTIAL, + a if a == wasi::ADVICE_RANDOM.raw() => wasi::ADVICE_RANDOM, + a if a == wasi::ADVICE_WILLNEED.raw() => wasi::ADVICE_WILLNEED, + a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED, + a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE, + _ => { + return Err(io::const_io_error!( + io::ErrorKind::InvalidInput, + "invalid parameter 'advice'", + )); + } + }; + + self.as_inner().as_inner().advise(offset, len, advice) + } + + fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { + self.as_inner().as_inner().allocate(offset, len) + } + + fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> { + self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?) + } + + fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> { + self.as_inner().read_link(path.as_ref()) + } + + fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> { + let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?; + Ok(FromInner::from_inner(m)) + } + + fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { + self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?) + } + + fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { + self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?) + } +} + +/// WASI-specific extensions to [`fs::OpenOptions`]. +pub trait OpenOptionsExt { + /// Pass custom `dirflags` argument to `path_open`. + /// + /// This option configures the `dirflags` argument to the + /// `path_open` syscall which `OpenOptions` will eventually call. The + /// `dirflags` argument configures how the file is looked up, currently + /// primarily affecting whether symlinks are followed or not. + /// + /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are + /// followed. You can call this method with 0 to disable following symlinks + fn lookup_flags(&mut self, flags: u32) -> &mut Self; + + /// Indicates whether `OpenOptions` must open a directory or not. + /// + /// This method will configure whether the `__WASI_O_DIRECTORY` flag is + /// passed when opening a file. When passed it will require that the opened + /// path is a directory. + /// + /// This option is by default `false` + fn directory(&mut self, dir: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags` + /// field of `path_open`. + /// + /// This option is by default `false` + fn dsync(&mut self, dsync: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags` + /// field of `path_open`. + /// + /// This option is by default `false` + fn nonblock(&mut self, nonblock: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags` + /// field of `path_open`. + /// + /// This option is by default `false` + fn rsync(&mut self, rsync: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags` + /// field of `path_open`. + /// + /// This option is by default `false` + fn sync(&mut self, sync: bool) -> &mut Self; + + /// Indicates the value that should be passed in for the `fs_rights_base` + /// parameter of `path_open`. + /// + /// This option defaults based on the `read` and `write` configuration of + /// this `OpenOptions` builder. If this method is called, however, the + /// exact mask passed in will be used instead. + fn fs_rights_base(&mut self, rights: u64) -> &mut Self; + + /// Indicates the value that should be passed in for the + /// `fs_rights_inheriting` parameter of `path_open`. + /// + /// The default for this option is the same value as what will be passed + /// for the `fs_rights_base` parameter but if this method is called then + /// the specified value will be used instead. + fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self; + + /// Open a file or directory. + /// + /// This corresponds to the `path_open` syscall. + fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>; +} + +impl OpenOptionsExt for OpenOptions { + fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions { + self.as_inner_mut().lookup_flags(flags); + self + } + + fn directory(&mut self, dir: bool) -> &mut OpenOptions { + self.as_inner_mut().directory(dir); + self + } + + fn dsync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().dsync(enabled); + self + } + + fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().nonblock(enabled); + self + } + + fn rsync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().rsync(enabled); + self + } + + fn sync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().sync(enabled); + self + } + + fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions { + self.as_inner_mut().fs_rights_base(rights); + self + } + + fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions { + self.as_inner_mut().fs_rights_inheriting(rights); + self + } + + fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> { + let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?; + Ok(File::from_inner(inner)) + } +} + +/// WASI-specific extensions to [`fs::Metadata`]. +pub trait MetadataExt { + /// Returns the `st_dev` field of the internal `filestat_t` + fn dev(&self) -> u64; + /// Returns the `st_ino` field of the internal `filestat_t` + fn ino(&self) -> u64; + /// Returns the `st_nlink` field of the internal `filestat_t` + fn nlink(&self) -> u64; + /// Returns the `st_size` field of the internal `filestat_t` + fn size(&self) -> u64; + /// Returns the `st_atim` field of the internal `filestat_t` + fn atim(&self) -> u64; + /// Returns the `st_mtim` field of the internal `filestat_t` + fn mtim(&self) -> u64; + /// Returns the `st_ctim` field of the internal `filestat_t` + fn ctim(&self) -> u64; +} + +impl MetadataExt for fs::Metadata { + fn dev(&self) -> u64 { + self.as_inner().as_wasi().dev + } + fn ino(&self) -> u64 { + self.as_inner().as_wasi().ino + } + fn nlink(&self) -> u64 { + self.as_inner().as_wasi().nlink + } + fn size(&self) -> u64 { + self.as_inner().as_wasi().size + } + fn atim(&self) -> u64 { + self.as_inner().as_wasi().atim + } + fn mtim(&self) -> u64 { + self.as_inner().as_wasi().mtim + } + fn ctim(&self) -> u64 { + self.as_inner().as_wasi().ctim + } +} + +/// WASI-specific extensions for [`fs::FileType`]. +/// +/// Adds support for special WASI file types such as block/character devices, +/// pipes, and sockets. +pub trait FileTypeExt { + /// Returns `true` if this file type is a block device. + fn is_block_device(&self) -> bool; + /// Returns `true` if this file type is a character device. + fn is_char_device(&self) -> bool; + /// Returns `true` if this file type is a socket datagram. + fn is_socket_dgram(&self) -> bool; + /// Returns `true` if this file type is a socket stream. + fn is_socket_stream(&self) -> bool; + /// Returns `true` if this file type is any type of socket. + fn is_socket(&self) -> bool { + self.is_socket_stream() || self.is_socket_dgram() + } +} + +impl FileTypeExt for fs::FileType { + fn is_block_device(&self) -> bool { + self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE + } + fn is_char_device(&self) -> bool { + self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE + } + fn is_socket_dgram(&self) -> bool { + self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM + } + fn is_socket_stream(&self) -> bool { + self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM + } +} + +/// WASI-specific extension methods for [`fs::DirEntry`]. +pub trait DirEntryExt { + /// Returns the underlying `d_ino` field of the `dirent_t` + fn ino(&self) -> u64; +} + +impl DirEntryExt for fs::DirEntry { + fn ino(&self) -> u64 { + self.as_inner().ino() + } +} + +/// Create a hard link. +/// +/// This corresponds to the `path_link` syscall. +pub fn link<P: AsRef<Path>, U: AsRef<Path>>( + old_fd: &File, + old_flags: u32, + old_path: P, + new_fd: &File, + new_path: U, +) -> io::Result<()> { + old_fd.as_inner().as_inner().link( + old_flags, + osstr2str(old_path.as_ref().as_ref())?, + new_fd.as_inner().as_inner(), + osstr2str(new_path.as_ref().as_ref())?, + ) +} + +/// Rename a file or directory. +/// +/// This corresponds to the `path_rename` syscall. +pub fn rename<P: AsRef<Path>, U: AsRef<Path>>( + old_fd: &File, + old_path: P, + new_fd: &File, + new_path: U, +) -> io::Result<()> { + old_fd.as_inner().as_inner().rename( + osstr2str(old_path.as_ref().as_ref())?, + new_fd.as_inner().as_inner(), + osstr2str(new_path.as_ref().as_ref())?, + ) +} + +/// Create a symbolic link. +/// +/// This corresponds to the `path_symlink` syscall. +pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>( + old_path: P, + fd: &File, + new_path: U, +) -> io::Result<()> { + fd.as_inner() + .as_inner() + .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?) +} + +/// Create a symbolic link. +/// +/// 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::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8")) +} diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs new file mode 100644 index 000000000..930aca887 --- /dev/null +++ b/library/std/src/os/wasi/io/fd.rs @@ -0,0 +1,9 @@ +//! Owned and borrowed file descriptors. + +#![unstable(feature = "wasi_ext", issue = "71213")] + +// Tests for this module +#[cfg(test)] +mod tests; + +pub use crate::os::fd::owned::*; diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/fd/tests.rs new file mode 100644 index 000000000..418274752 --- /dev/null +++ b/library/std/src/os/wasi/io/fd/tests.rs @@ -0,0 +1,11 @@ +use crate::mem::size_of; +use crate::os::wasi::io::RawFd; + +#[test] +fn test_raw_fd_layout() { + // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start` + // and `rustc_layout_scalar_valid_range_end`, with values that depend on + // the bit width of `RawFd`. If this ever changes, those values will need + // to be updated. + assert_eq!(size_of::<RawFd>(), 4); +} diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs new file mode 100644 index 000000000..6c884e2ea --- /dev/null +++ b/library/std/src/os/wasi/io/mod.rs @@ -0,0 +1,12 @@ +//! WASI-specific extensions to general I/O primitives. + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "wasi_ext", issue = "71213")] + +mod fd; +mod raw; + +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use fd::*; +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use raw::*; diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs new file mode 100644 index 000000000..da3b36ada --- /dev/null +++ b/library/std/src/os/wasi/io/raw.rs @@ -0,0 +1,20 @@ +//! WASI-specific extensions to general I/O primitives. + +#![unstable(feature = "wasi_ext", issue = "71213")] + +// NOTE: despite the fact that this module is unstable, +// stable Rust had the capability to access the stable +// re-exported items from os::fd::raw through this +// unstable module. +// In PR #95956 the stability checker was changed to check +// all path segments of an item rather than just the last, +// which caused the aforementioned stable usage to regress +// (see issue #99502). +// As a result, the items in os::fd::raw were given the +// rustc_allowed_through_unstable_modules attribute. +// No regression tests were added to ensure this property, +// as CI is not configured to test wasm32-wasi. +// If this module is stabilized, +// you may want to remove those attributes +// (assuming no other unstable modules need them). +pub use crate::os::fd::raw::*; diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs new file mode 100644 index 000000000..bbaf328f4 --- /dev/null +++ b/library/std/src/os/wasi/mod.rs @@ -0,0 +1,57 @@ +//! Platform-specific extensions to `std` for the WebAssembly System Interface (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(()) +//! } +//! ``` +//! +//! [`OsStr`]: crate::ffi::OsStr +//! [`OsString`]: crate::ffi::OsString + +#![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] +#![doc(cfg(target_os = "wasi"))] + +pub mod ffi; +pub mod fs; +pub mod io; +pub mod net; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::fs::FileTypeExt; + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt}; + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +} diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs new file mode 100644 index 000000000..73c097d4a --- /dev/null +++ b/library/std/src/os/wasi/net/mod.rs @@ -0,0 +1,23 @@ +//! WASI-specific networking functionality + +#![unstable(feature = "wasi_ext", issue = "71213")] + +use crate::io; +use crate::net; +use crate::sys_common::AsInner; + +/// WASI-specific extensions to [`std::net::TcpListener`]. +/// +/// [`std::net::TcpListener`]: crate::net::TcpListener +pub trait TcpListenerExt { + /// Accept a socket. + /// + /// This corresponds to the `sock_accept` syscall. + fn sock_accept(&self, flags: u16) -> io::Result<u32>; +} + +impl TcpListenerExt for net::TcpListener { + fn sock_accept(&self, flags: u16) -> io::Result<u32> { + self.as_inner().as_inner().as_inner().sock_accept(flags) + } +} |