diff options
Diffstat (limited to 'library/std/src')
29 files changed, 510 insertions, 54 deletions
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 1214490caad..a39565d2159 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -828,7 +828,8 @@ impl OsStr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new<S: [const] AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr { s.as_ref() } @@ -876,14 +877,16 @@ impl OsStr { } #[inline] - fn from_inner(inner: &Slice) -> &OsStr { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner(inner: &Slice) -> &OsStr { // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] - fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. // Any method that mutates OsStr must be careful not to @@ -1681,7 +1684,8 @@ impl ToOwned for OsStr { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<OsStr> for OsStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<OsStr> for OsStr { #[inline] fn as_ref(&self) -> &OsStr { self diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 5e51d5e5211..f4431cedd18 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -492,6 +492,85 @@ fn file_test_io_read_write_at() { #[test] #[cfg(unix)] +fn test_read_buf_at() { + use crate::os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_buf_at.txt"); + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut file = check!(oo.open(&filename)); + check!(file.write_all(b"0123456789")); + } + { + let mut file = check!(File::open(&filename)); + let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5]; + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + + // Fill entire buffer with potentially short reads + while buf.unfilled().capacity() > 0 { + let len = buf.len(); + check!(file.read_buf_at(buf.unfilled(), 2 + len as u64)); + assert!(!buf.filled().is_empty()); + assert!(b"23456".starts_with(buf.filled())); + assert_eq!(check!(file.stream_position()), 0); + } + assert_eq!(buf.filled(), b"23456"); + + // Already full + check!(file.read_buf_at(buf.unfilled(), 3)); + check!(file.read_buf_at(buf.unfilled(), 10)); + assert_eq!(buf.filled(), b"23456"); + assert_eq!(check!(file.stream_position()), 0); + + // Read past eof is noop + check!(file.read_buf_at(buf.clear().unfilled(), 10)); + assert_eq!(buf.filled(), b""); + check!(file.read_buf_at(buf.clear().unfilled(), 11)); + assert_eq!(buf.filled(), b""); + assert_eq!(check!(file.stream_position()), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] +fn test_read_buf_exact_at() { + use crate::os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_buf_exact_at.txt"); + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut file = check!(oo.open(&filename)); + check!(file.write_all(b"0123456789")); + } + { + let mut file = check!(File::open(&filename)); + let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5]; + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + + // Exact read + check!(file.read_buf_exact_at(buf.unfilled(), 2)); + assert_eq!(buf.filled(), b"23456"); + assert_eq!(check!(file.stream_position()), 0); + + // Already full + check!(file.read_buf_exact_at(buf.unfilled(), 3)); + check!(file.read_buf_exact_at(buf.unfilled(), 10)); + assert_eq!(buf.filled(), b"23456"); + assert_eq!(check!(file.stream_position()), 0); + + // Non-empty exact read past eof fails + let err = file.read_buf_exact_at(buf.clear().unfilled(), 6).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::UnexpectedEof); + assert_eq!(check!(file.stream_position()), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] fn set_get_unix_permissions() { use crate::os::unix::fs::PermissionsExt; @@ -567,6 +646,39 @@ fn file_test_io_seek_read_write() { } #[test] +#[cfg(windows)] +fn test_seek_read_buf() { + use crate::os::windows::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf.txt"); + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut file = check!(oo.open(&filename)); + check!(file.write_all(b"0123456789")); + } + { + let mut file = check!(File::open(&filename)); + let mut buf: [MaybeUninit<u8>; 1] = [MaybeUninit::uninit()]; + let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + + // Seek read + check!(file.seek_read_buf(buf.unfilled(), 8)); + assert_eq!(buf.filled(), b"8"); + assert_eq!(check!(file.stream_position()), 9); + + // Empty seek read + check!(file.seek_read_buf(buf.unfilled(), 0)); + assert_eq!(buf.filled(), b"8"); + + // Seek read past eof + check!(file.seek_read_buf(buf.clear().unfilled(), 10)); + assert_eq!(buf.filled(), b""); + } + check!(fs::remove_file(&filename)); +} + +#[test] fn file_test_read_buf() { let tmpdir = tmpdir(); let filename = &tmpdir.join("test"); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3771699c59f..a4b63462053 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -290,7 +290,6 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(extended_varargs_abi_support)] #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] @@ -333,6 +332,7 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_cmp)] +#![feature(const_convert)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_try)] diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index b776df3dde1..1d1a138b302 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -11,6 +11,7 @@ use super::platform::fs::MetadataExt as _; // Used for `File::read` on intra-doc links use crate::ffi::OsStr; use crate::fs::{self, OpenOptions, Permissions}; +use crate::io::BorrowedCursor; use crate::os::unix::io::{AsFd, AsRawFd}; use crate::path::Path; use crate::sealed::Sealed; @@ -130,6 +131,91 @@ pub trait FileExt { if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } } + /// Reads some bytes starting from a given offset into the buffer. + /// + /// This equivalent to the [`read_at`](FileExt::read_at) method, except that it is passed a + /// [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The new + /// data will be appended to any existing contents of `buf`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(core_io_borrowed_buf)] + /// #![feature(read_buf_at)] + /// + /// use std::io; + /// use std::io::BorrowedBuf; + /// use std::fs::File; + /// use std::mem::MaybeUninit; + /// use std::os::unix::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("pi.txt")?; + /// + /// // Read some bytes starting from offset 2 + /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; + /// let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + /// file.read_buf_at(buf.unfilled(), 2)?; + /// + /// assert!(buf.filled().starts_with(b"1")); + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_buf_at", issue = "140771")] + fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + io::default_read_buf(|b| self.read_at(b, offset), buf) + } + + /// Reads the exact number of bytes required to fill the buffer from a given offset. + /// + /// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method, except that it + /// is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized + /// buffers. The new data will be appended to any existing contents of `buf`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(core_io_borrowed_buf)] + /// #![feature(read_buf_at)] + /// + /// use std::io; + /// use std::io::BorrowedBuf; + /// use std::fs::File; + /// use std::mem::MaybeUninit; + /// use std::os::unix::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("pi.txt")?; + /// + /// // Read exactly 10 bytes starting from offset 2 + /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; + /// let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + /// file.read_buf_exact_at(buf.unfilled(), 2)?; + /// + /// assert_eq!(buf.filled(), b"1415926535"); + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_buf_at", issue = "140771")] + fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> { + while buf.capacity() > 0 { + let prev_written = buf.written(); + match self.read_buf_at(buf.reborrow(), offset) { + Ok(()) => {} + Err(e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + let n = buf.written() - prev_written; + offset += n as u64; + if n == 0 { + return Err(io::Error::READ_EXACT_EOF); + } + } + Ok(()) + } + /// Writes a number of bytes starting from a given offset. /// /// Returns the number of bytes written. @@ -264,6 +350,9 @@ impl FileExt for fs::File { fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.as_inner().read_at(buf, offset) } + fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.as_inner().read_buf_at(buf, offset) + } fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { self.as_inner().read_vectored_at(bufs, offset) } diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index ddb8dbd8fee..b445f368aeb 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -5,6 +5,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fs::{self, Metadata, OpenOptions}; +use crate::io::BorrowedCursor; use crate::path::Path; use crate::sealed::Sealed; use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; @@ -49,6 +50,44 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; + /// Seeks to a given position and reads some bytes into the buffer. + /// + /// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except that it is passed + /// a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The + /// new data will be appended to any existing contents of `buf`. + /// + /// Reading beyond the end of the file will always succeed without reading any bytes. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(core_io_borrowed_buf)] + /// #![feature(read_buf_at)] + /// + /// use std::io; + /// use std::io::BorrowedBuf; + /// use std::fs::File; + /// use std::mem::MaybeUninit; + /// use std::os::windows::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("pi.txt")?; + /// + /// // Read some bytes starting from offset 2 + /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10]; + /// let mut buf = BorrowedBuf::from(buf.as_mut_slice()); + /// file.seek_read_buf(buf.unfilled(), 2)?; + /// + /// assert!(buf.filled().starts_with(b"1")); + /// + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "read_buf_at", issue = "140771")] + fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + io::default_read_buf(|b| self.seek_read(b, offset), buf) + } + /// Seeks to a given position and writes a number of bytes. /// /// Returns the number of bytes written. @@ -89,6 +128,10 @@ impl FileExt for fs::File { self.as_inner().read_at(buf, offset) } + fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.as_inner().read_buf_at(buf, offset) + } + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.as_inner().write_at(buf, offset) } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 87a3fc80dfa..8b7282c51d1 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -819,7 +819,7 @@ fn panic_with_hook( rtprintpanic!("aborting due to panic at {location}:\n{payload}\n"); } } - crate::sys::abort_internal(); + crate::process::abort(); } match *HOOK.read().unwrap_or_else(PoisonError::into_inner) { @@ -853,7 +853,7 @@ fn panic_with_hook( // through a nounwind function (e.g. extern "C") then we cannot continue // unwinding and have to abort immediately. rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); - crate::sys::abort_internal(); + crate::process::abort(); } rust_panic(payload) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 470d300d2d9..531a1aa4215 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1575,8 +1575,6 @@ impl PathBuf { /// # Examples /// /// ``` - /// #![feature(path_add_extension)] - /// /// use std::path::{Path, PathBuf}; /// /// let mut p = PathBuf::from("/feel/the"); @@ -1596,7 +1594,7 @@ impl PathBuf { /// p.add_extension(""); /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); /// ``` - #[unstable(feature = "path_add_extension", issue = "127292")] + #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool { self._add_extension(extension.as_ref()) } @@ -2264,11 +2262,13 @@ impl Path { /// assert_eq!(from_string, from_path); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new<S: [const] AsRef<OsStr> + ?Sized>(s: &S) -> &Path { unsafe { &*(s.as_ref() as *const OsStr as *const Path) } } - fn from_inner_mut(inner: &mut OsStr) -> &mut Path { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner_mut(inner: &mut OsStr) -> &mut Path { // SAFETY: Path is just a wrapper around OsStr, // therefore converting &mut OsStr to &mut Path is safe. unsafe { &mut *(inner as *mut OsStr as *mut Path) } @@ -2878,8 +2878,6 @@ impl Path { /// # Examples /// /// ``` - /// #![feature(path_add_extension)] - /// /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("foo.rs"); @@ -2890,7 +2888,7 @@ impl Path { /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz")); /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt")); /// ``` - #[unstable(feature = "path_add_extension", issue = "127292")] + #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { let mut new_path = self.to_path_buf(); new_path.add_extension(extension); @@ -3337,7 +3335,8 @@ unsafe impl CloneToUninit for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<OsStr> for Path { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<OsStr> for Path { #[inline] fn as_ref(&self) -> &OsStr { &self.inner @@ -3507,7 +3506,8 @@ impl Ord for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<Path> for Path { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<Path> for Path { #[inline] fn as_ref(&self) -> &Path { self @@ -3515,7 +3515,8 @@ impl AsRef<Path> for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<Path> for OsStr { +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef<Path> for OsStr { #[inline] fn as_ref(&self) -> &Path { Path::new(self) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 373584d0117..48265de90c4 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2495,6 +2495,7 @@ pub fn exit(code: i32) -> ! { #[stable(feature = "process_abort", since = "1.17.0")] #[cold] #[cfg_attr(not(test), rustc_diagnostic_item = "process_abort")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn abort() -> ! { crate::sys::abort_internal(); } diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index c9627322276..e11e8e5430f 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -32,9 +32,13 @@ cfg_select! { mod uefi; pub use uefi::*; } - target_os = "wasi" => { - mod wasi; - pub use wasi::*; + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use wasip1::*; + } + all(target_os = "wasi", target_env = "p2") => { + mod wasip2; + pub use wasip2::*; } target_os = "xous" => { mod xous; diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasip1.rs index 72063a87dc9..72063a87dc9 100644 --- a/library/std/src/sys/args/wasi.rs +++ b/library/std/src/sys/args/wasip1.rs diff --git a/library/std/src/sys/args/wasip2.rs b/library/std/src/sys/args/wasip2.rs new file mode 100644 index 00000000000..a57e4b97786 --- /dev/null +++ b/library/std/src/sys/args/wasip2.rs @@ -0,0 +1,6 @@ +pub use super::common::Args; + +/// Returns the command line arguments +pub fn args() -> Args { + Args::new(wasip2::cli::environment::get_arguments().into_iter().map(|arg| arg.into()).collect()) +} diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index a12f692e754..2b2dfe48e89 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -18,6 +18,21 @@ use libc::off_t as off64_t; ))] use libc::off64_t; +cfg_select! { + any( + all(target_os = "linux", not(target_env = "musl")), + target_os = "android", + target_os = "hurd", + ) => { + // Prefer explicit pread64 for 64-bit offset independently of libc + // #[cfg(gnu_file_offset_bits64)]. + use libc::pread64; + } + _ => { + use libc::pread as pread64; + } +} + use crate::cmp; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; @@ -146,42 +161,47 @@ impl FileDesc { (&mut me).read_to_end(buf) } - #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - #[cfg(not(any( - all(target_os = "linux", not(target_env = "musl")), - target_os = "android", - target_os = "hurd" - )))] - use libc::pread as pread64; - #[cfg(any( - all(target_os = "linux", not(target_env = "musl")), - target_os = "android", - target_os = "hurd" - ))] - use libc::pread64; - - unsafe { - cvt(pread64( + cvt(unsafe { + pread64( self.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, cmp::min(buf.len(), READ_LIMIT), - offset as off64_t, - )) - .map(|n| n as usize) - } + offset as off64_t, // EINVAL if offset + count overflows + ) + }) + .map(|n| n as usize) } pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { + // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes let ret = cvt(unsafe { libc::read( self.as_raw_fd(), - cursor.as_mut().as_mut_ptr() as *mut libc::c_void, + cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(), + cmp::min(cursor.capacity(), READ_LIMIT), + ) + })?; + + // SAFETY: `ret` bytes were written to the initialized portion of the buffer + unsafe { + cursor.advance_unchecked(ret as usize); + } + Ok(()) + } + + pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes + let ret = cvt(unsafe { + pread64( + self.as_raw_fd(), + cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(), cmp::min(cursor.capacity(), READ_LIMIT), + offset as off64_t, // EINVAL if offset + count overflows ) })?; - // Safety: `ret` bytes were written to the initialized portion of the buffer + // SAFETY: `ret` bytes were written to the initialized portion of the buffer unsafe { cursor.advance_unchecked(ret as usize); } @@ -369,7 +389,6 @@ impl FileDesc { ))) } - #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))] pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index a89c3bbacfb..3b525406223 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1463,6 +1463,10 @@ impl File { self.0.read_buf(cursor) } + pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.0.read_buf_at(cursor, offset) + } + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { self.0.read_vectored_at(bufs, offset) } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index bac278f7c8f..ccfe410627f 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -605,6 +605,10 @@ impl File { self.handle.read_buf(cursor) } + pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + self.handle.read_buf_at(cursor, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.handle.write(buf) } diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 9376f5249f1..513121c6d30 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -49,9 +49,9 @@ cfg_select! { mod wasip2; pub use self::wasip2::*; } - target_os = "wasi" => { - mod wasi; - pub use self::wasi::*; + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use self::wasip1::*; } target_family = "wasm" => { mod wasm; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 400128acf12..ac5c823a1bf 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -364,6 +364,7 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { // multithreaded C program. It is much less severe for Rust, because Rust // stdlib doesn't use libc stdio buffering. In a typical Rust program, which // does not use C stdio, even a buggy libc::abort() is, in fact, safe. +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn abort_internal() -> ! { unsafe { libc::abort() } } diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasip1/helpers.rs index 404747f0dc7..404747f0dc7 100644 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ b/library/std/src/sys/pal/wasip1/helpers.rs diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasip1/mod.rs index 61dd1c3f98b..61dd1c3f98b 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasip1/mod.rs diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasip1/os.rs index 151ba254ec4..151ba254ec4 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasip1/os.rs diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasip1/thread.rs index e062b49bd7a..e062b49bd7a 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasip1/thread.rs diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasip1/time.rs index 892661b312b..892661b312b 100644 --- a/library/std/src/sys/pal/wasi/time.rs +++ b/library/std/src/sys/pal/wasip1/time.rs diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 47fe3221c90..5f3fb6d6ddf 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -10,13 +10,11 @@ #[path = "../wasm/atomics/futex.rs"] pub mod futex; -#[path = "../wasi/os.rs"] +#[path = "../wasip1/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../wasi/thread.rs"] pub mod thread; -#[path = "../wasi/time.rs"] pub mod time; #[path = "../unsupported/common.rs"] @@ -26,7 +24,7 @@ mod common; pub use common::*; -#[path = "../wasi/helpers.rs"] +#[path = "../wasip1/helpers.rs"] mod helpers; // The following exports are listed individually to work around Rust's glob diff --git a/library/std/src/sys/pal/wasip2/thread.rs b/library/std/src/sys/pal/wasip2/thread.rs new file mode 100644 index 00000000000..ad52918f15a --- /dev/null +++ b/library/std/src/sys/pal/wasip2/thread.rs @@ -0,0 +1,73 @@ +use crate::ffi::CStr; +use crate::io; +use crate::num::NonZero; +use crate::time::{Duration, Instant}; + +pub struct Thread(!); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; + +impl Thread { + pub unsafe fn new( + _stack: usize, + _name: Option<&str>, + _p: Box<dyn FnOnce()>, + ) -> io::Result<Thread> { + // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled + // there is no support for threads, not even experimentally, not even in + // wasi-libc. Thus this is unconditionally unsupported. + crate::sys::unsupported() + } + + pub fn yield_now() { + // no API for this in WASIp2, but there's also no threads, so that's + // sort of expected. + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is + // entirely drained. + let mut remaining = dur.as_nanos(); + while remaining > 0 { + let amt = u64::try_from(remaining).unwrap_or(u64::MAX); + wasip2::clocks::monotonic_clock::subscribe_duration(amt).block(); + remaining -= u128::from(amt); + } + } + + pub fn sleep_until(deadline: Instant) { + match u64::try_from(deadline.into_inner().as_duration().as_nanos()) { + // If the point in time we're sleeping to fits within a 64-bit + // number of nanoseconds then directly use `subscribe_instant`. + Ok(deadline) => { + wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block(); + } + // ... otherwise we're sleeping for 500+ years relative to the + // "start" of what the system is using as a clock so speed/accuracy + // is not so much of a concern. Use `sleep` instead. + Err(_) => { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + Self::sleep(delay); + } + } + } + } + + pub fn join(self) { + self.0 + } +} + +pub(crate) fn current_os_id() -> Option<u64> { + None +} + +pub fn available_parallelism() -> io::Result<NonZero<usize>> { + crate::sys::unsupported() +} diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs new file mode 100644 index 00000000000..f1f6839774b --- /dev/null +++ b/library/std/src/sys/pal/wasip2/time.rs @@ -0,0 +1,69 @@ +use crate::time::Duration; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); + +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); + +impl Instant { + pub fn now() -> Instant { + Instant(Duration::from_nanos(wasip2::clocks::monotonic_clock::now())) + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { + self.0.checked_sub(other.0) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { + Some(Instant(self.0.checked_add(*other)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { + Some(Instant(self.0.checked_sub(*other)?)) + } + + pub(super) fn as_duration(&self) -> &Duration { + &self.0 + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + let now = wasip2::clocks::wall_clock::now(); + SystemTime(Duration::new(now.seconds, now.nanoseconds)) + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { + SystemTime(Duration::from_nanos(ts)) + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> { + // FIXME: const TryInto + let ns = self.0.as_nanos(); + if ns <= u64::MAX as u128 { Some(ns as u64) } else { None } + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + Some(SystemTime(self.0.checked_add(*other)?)) + } + + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + Some(SystemTime(self.0.checked_sub(*other)?)) + } +} diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 82a880faf5f..76c8aa939d3 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -136,6 +136,19 @@ impl Handle { } } + pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> { + // SAFETY: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes + let read = unsafe { + self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset)) + }?; + + // SAFETY: `read` bytes were written to the initialized portion of the buffer + unsafe { + cursor.advance_unchecked(read); + } + Ok(()) + } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { let mut me = self; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 10ad4541bed..3b6a86cbc8f 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -356,6 +356,7 @@ pub fn abort_internal() -> ! { } #[cfg(miri)] +#[track_caller] // even without panics, this helps for Miri backtraces pub fn abort_internal() -> ! { crate::intrinsics::abort(); } diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index a7fbae86099..1e0eec07b50 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -86,9 +86,13 @@ cfg_select! { mod vxworks; pub use vxworks::fill_bytes; } - target_os = "wasi" => { - mod wasi; - pub use wasi::fill_bytes; + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use wasip1::fill_bytes; + } + all(target_os = "wasi", target_env = "p2") => { + mod wasip2; + pub use wasip2::{fill_bytes, hashmap_random_keys}; } target_os = "zkvm" => { mod zkvm; @@ -110,6 +114,7 @@ cfg_select! { target_os = "linux", target_os = "android", all(target_family = "wasm", target_os = "unknown"), + all(target_os = "wasi", target_env = "p2"), target_os = "xous", )))] pub fn hashmap_random_keys() -> (u64, u64) { diff --git a/library/std/src/sys/random/wasi.rs b/library/std/src/sys/random/wasip1.rs index d41da3751fc..d41da3751fc 100644 --- a/library/std/src/sys/random/wasi.rs +++ b/library/std/src/sys/random/wasip1.rs diff --git a/library/std/src/sys/random/wasip2.rs b/library/std/src/sys/random/wasip2.rs new file mode 100644 index 00000000000..a67c8a6428d --- /dev/null +++ b/library/std/src/sys/random/wasip2.rs @@ -0,0 +1,9 @@ +pub fn fill_bytes(bytes: &mut [u8]) { + bytes.copy_from_slice(&wasip2::random::random::get_random_bytes( + u64::try_from(bytes.len()).unwrap(), + )); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + wasip2::random::insecure_seed::insecure_seed() +} |
