diff options
Diffstat (limited to 'library/std')
73 files changed, 1433 insertions, 473 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d28a7f0b460..888914a2f77 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -62,7 +62,7 @@ path = "../windows_targets" rand = { version = "0.9.0", default-features = false, features = ["alloc"] } rand_xorshift = "0.4.0" -[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] +[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", target_os = "vexos", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.10", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] @@ -89,6 +89,11 @@ wasip2 = { version = '0.14.4', features = [ r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] } +[target.'cfg(target_os = "vexos")'.dependencies] +vex-sdk = { version = "0.27.0", features = [ + 'rustc-dep-of-std', +], default-features = false } + [features] backtrace = [ 'addr2line/rustc-dep-of-std', @@ -106,11 +111,6 @@ compiler-builtins-no-f16-f128 = ["alloc/compiler-builtins-no-f16-f128"] llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] -# Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = [ - "core/panic_immediate_abort", - "alloc/panic_immediate_abort", -] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] diff --git a/library/std/build.rs b/library/std/build.rs index ef695601a44..8a5a785060c 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -52,6 +52,7 @@ fn main() { || target_os == "rtems" || target_os == "nuttx" || target_os == "cygwin" + || target_os == "vexos" // See src/bootstrap/src/core/build_steps/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() diff --git a/library/std/src/env.rs b/library/std/src/env.rs index e457cd61c75..6d716bd8544 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -1098,6 +1098,7 @@ pub mod consts { /// * `"redox"` /// * `"solaris"` /// * `"solid_asp3` + /// * `"vexos"` /// * `"vita"` /// * `"vxworks"` /// * `"xous"` @@ -1148,6 +1149,7 @@ pub mod consts { /// /// <details><summary>Full list of possible values</summary> /// + /// * `"bin"` /// * `"exe"` /// * `"efi"` /// * `"js"` diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index a39565d2159..6c098034eea 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -137,7 +137,7 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "1.91.0")] pub const fn new() -> OsString { OsString { inner: Buf::from_string(String::new()) } } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ff0e29e04c2..a45edd08e8c 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1081,7 +1081,7 @@ pub trait Read { default_read_buf_exact(self, cursor) } - /// Creates a "by reference" adaptor for this instance of `Read`. + /// Creates a "by reference" adapter for this instance of `Read`. /// /// The returned adapter also implements `Read` and will simply borrow this /// current reader. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 33e3bf0c085..61b7d170b8b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -235,7 +235,7 @@ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] #![doc(rust_logo)] -#![doc(cfg_hide(not(test), no_global_oom_handling, not(no_global_oom_handling)))] +#![doc(auto_cfg(hide(no_global_oom_handling)))] // Don't link to std. We are std. #![no_std] // Tell the compiler to link to either panic_abort or panic_unwind @@ -285,7 +285,6 @@ #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] -#![feature(doc_cfg_hide)] #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] @@ -332,6 +331,7 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_convert)] +#![feature(const_mul_add)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(drop_guard)] @@ -381,7 +381,6 @@ #![feature(allocator_api)] #![feature(get_mut_unchecked)] #![feature(map_try_insert)] -#![feature(new_zeroed_alloc)] #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs index 41e623e79ce..8214ad381f1 100644 --- a/library/std/src/net/socket_addr.rs +++ b/library/std/src/net/socket_addr.rs @@ -6,7 +6,6 @@ mod tests; pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use crate::sys::net::LookupHost; use crate::{io, iter, option, slice, vec}; /// A trait for objects which can be converted or resolved to one or more @@ -29,6 +28,8 @@ use crate::{io, iter, option, slice, vec}; /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like /// `<host_name>:<port>` pair where `<port>` is a [`u16`] value. /// +/// * <code>&[[SocketAddr]]</code>: all [`SocketAddr`] values in the slice will be used. +/// /// This trait allows constructing network objects like [`TcpStream`] or /// [`UdpSocket`] easily with values of various types for the bind/connection /// address. It is needed because sometimes one type is more appropriate than @@ -188,15 +189,9 @@ impl ToSocketAddrs for (Ipv6Addr, u16) { } } -fn resolve_socket_addr(lh: LookupHost) -> io::Result<vec::IntoIter<SocketAddr>> { - let p = lh.port(); - let v: Vec<_> = lh - .map(|mut a| { - a.set_port(p); - a - }) - .collect(); - Ok(v.into_iter()) +fn lookup_host(host: &str, port: u16) -> io::Result<vec::IntoIter<SocketAddr>> { + let addrs = crate::sys::net::lookup_host(host, port)?; + Ok(Vec::from_iter(addrs).into_iter()) } #[stable(feature = "rust1", since = "1.0.0")] @@ -205,17 +200,14 @@ impl ToSocketAddrs for (&str, u16) { fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> { let (host, port) = *self; - // try to parse the host as a regular IP address first - if let Ok(addr) = host.parse::<Ipv4Addr>() { - let addr = SocketAddrV4::new(addr, port); - return Ok(vec![SocketAddr::V4(addr)].into_iter()); - } - if let Ok(addr) = host.parse::<Ipv6Addr>() { - let addr = SocketAddrV6::new(addr, port, 0, 0); - return Ok(vec![SocketAddr::V6(addr)].into_iter()); + // Try to parse the host as a regular IP address first + if let Ok(addr) = host.parse::<IpAddr>() { + let addr = SocketAddr::new(addr, port); + return Ok(vec![addr].into_iter()); } - resolve_socket_addr((host, port).try_into()?) + // Otherwise, make the system look it up. + lookup_host(host, port) } } @@ -232,12 +224,21 @@ impl ToSocketAddrs for (String, u16) { impl ToSocketAddrs for str { type Iter = vec::IntoIter<SocketAddr>; fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> { - // try to parse as a regular SocketAddr first + // Try to parse as a regular SocketAddr first if let Ok(addr) = self.parse() { return Ok(vec![addr].into_iter()); } - resolve_socket_addr(self.try_into()?) + // Otherwise, split the string by ':' and convert the second part to u16... + let Some((host, port_str)) = self.rsplit_once(':') else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid socket address")); + }; + let Ok(port) = port_str.parse::<u16>() else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid port value")); + }; + + // ... and make the system look up the host. + lookup_host(host, port) } } diff --git a/library/std/src/num/f128.rs b/library/std/src/num/f128.rs index b83692390b6..5d206c4b7da 100644 --- a/library/std/src/num/f128.rs +++ b/library/std/src/num/f128.rs @@ -44,7 +44,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powf(self, n: f128) -> f128 { - unsafe { intrinsics::powf128(self, n) } + intrinsics::powf128(self, n) } /// Returns `e^(self)`, (the exponential function). @@ -76,7 +76,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp(self) -> f128 { - unsafe { intrinsics::expf128(self) } + intrinsics::expf128(self) } /// Returns `2^(self)`. @@ -106,7 +106,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp2(self) -> f128 { - unsafe { intrinsics::exp2f128(self) } + intrinsics::exp2f128(self) } /// Returns the natural logarithm of the number. @@ -151,7 +151,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln(self) -> f128 { - unsafe { intrinsics::logf128(self) } + intrinsics::logf128(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -241,7 +241,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log2(self) -> f128 { - unsafe { intrinsics::log2f128(self) } + intrinsics::log2f128(self) } /// Returns the base 10 logarithm of the number. @@ -284,7 +284,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log10(self) -> f128 { - unsafe { intrinsics::log10f128(self) } + intrinsics::log10f128(self) } /// Returns the cube root of a number. @@ -385,7 +385,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sin(self) -> f128 { - unsafe { intrinsics::sinf128(self) } + intrinsics::sinf128(self) } /// Computes the cosine of a number (in radians). @@ -414,7 +414,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cos(self) -> f128 { - unsafe { intrinsics::cosf128(self) } + intrinsics::cosf128(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 5599528717c..2565ef0f9f2 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -44,7 +44,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn powf(self, n: f16) -> f16 { - unsafe { intrinsics::powf16(self, n) } + intrinsics::powf16(self, n) } /// Returns `e^(self)`, (the exponential function). @@ -76,7 +76,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp(self) -> f16 { - unsafe { intrinsics::expf16(self) } + intrinsics::expf16(self) } /// Returns `2^(self)`. @@ -106,7 +106,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn exp2(self) -> f16 { - unsafe { intrinsics::exp2f16(self) } + intrinsics::exp2f16(self) } /// Returns the natural logarithm of the number. @@ -151,7 +151,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln(self) -> f16 { - unsafe { intrinsics::logf16(self) } + intrinsics::logf16(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -241,7 +241,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log2(self) -> f16 { - unsafe { intrinsics::log2f16(self) } + intrinsics::log2f16(self) } /// Returns the base 10 logarithm of the number. @@ -284,7 +284,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn log10(self) -> f16 { - unsafe { intrinsics::log10f16(self) } + intrinsics::log10f16(self) } /// Compute the distance between the origin and a point (`x`, `y`) on the @@ -350,7 +350,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn sin(self) -> f16 { - unsafe { intrinsics::sinf16(self) } + intrinsics::sinf16(self) } /// Computes the cosine of a number (in radians). @@ -379,7 +379,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn cos(self) -> f16 { - unsafe { intrinsics::cosf16(self) } + intrinsics::cosf16(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs index 0247080a8d6..e7810e77e76 100644 --- a/library/std/src/num/f32.rs +++ b/library/std/src/num/f32.rs @@ -217,7 +217,8 @@ impl f32 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn mul_add(self, a: f32, b: f32) -> f32 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f32, b: f32) -> f32 { core::f32::math::mul_add(self, a, b) } @@ -338,7 +339,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powf(self, n: f32) -> f32 { - unsafe { intrinsics::powf32(self, n) } + intrinsics::powf32(self, n) } /// Returns the square root of a number. @@ -395,7 +396,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp(self) -> f32 { - unsafe { intrinsics::expf32(self) } + intrinsics::expf32(self) } /// Returns `2^(self)`. @@ -420,7 +421,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp2(self) -> f32 { - unsafe { intrinsics::exp2f32(self) } + intrinsics::exp2f32(self) } /// Returns the natural logarithm of the number. @@ -455,7 +456,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f32 { - unsafe { intrinsics::logf32(self) } + intrinsics::logf32(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -525,7 +526,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f32 { - unsafe { intrinsics::log2f32(self) } + intrinsics::log2f32(self) } /// Returns the base 10 logarithm of the number. @@ -558,7 +559,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f32 { - unsafe { intrinsics::log10f32(self) } + intrinsics::log10f32(self) } /// The positive difference of two numbers. @@ -683,7 +684,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sin(self) -> f32 { - unsafe { intrinsics::sinf32(self) } + intrinsics::sinf32(self) } /// Computes the cosine of a number (in radians). @@ -707,7 +708,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cos(self) -> f32 { - unsafe { intrinsics::cosf32(self) } + intrinsics::cosf32(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs index 1cfd3909d96..cbebbfb1be1 100644 --- a/library/std/src/num/f64.rs +++ b/library/std/src/num/f64.rs @@ -217,7 +217,8 @@ impl f64 { #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn mul_add(self, a: f64, b: f64) -> f64 { + #[rustc_const_unstable(feature = "const_mul_add", issue = "146724")] + pub const fn mul_add(self, a: f64, b: f64) -> f64 { core::f64::math::mul_add(self, a, b) } @@ -338,7 +339,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn powf(self, n: f64) -> f64 { - unsafe { intrinsics::powf64(self, n) } + intrinsics::powf64(self, n) } /// Returns the square root of a number. @@ -395,7 +396,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp(self) -> f64 { - unsafe { intrinsics::expf64(self) } + intrinsics::expf64(self) } /// Returns `2^(self)`. @@ -420,7 +421,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn exp2(self) -> f64 { - unsafe { intrinsics::exp2f64(self) } + intrinsics::exp2f64(self) } /// Returns the natural logarithm of the number. @@ -455,7 +456,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn ln(self) -> f64 { - unsafe { intrinsics::logf64(self) } + intrinsics::logf64(self) } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -525,7 +526,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - unsafe { intrinsics::log2f64(self) } + intrinsics::log2f64(self) } /// Returns the base 10 logarithm of the number. @@ -558,7 +559,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log10(self) -> f64 { - unsafe { intrinsics::log10f64(self) } + intrinsics::log10f64(self) } /// The positive difference of two numbers. @@ -683,7 +684,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sin(self) -> f64 { - unsafe { intrinsics::sinf64(self) } + intrinsics::sinf64(self) } /// Computes the cosine of a number (in radians). @@ -707,7 +708,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cos(self) -> f64 { - unsafe { intrinsics::cosf64(self) } + intrinsics::cosf64(self) } /// Computes the tangent of a number (in radians). diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs index 3b1bd974fa3..ff184f477fb 100644 --- a/library/std/src/os/darwin/mod.rs +++ b/library/std/src/os/darwin/mod.rs @@ -17,6 +17,8 @@ #![doc(cfg(target_vendor = "apple"))] pub mod fs; +pub mod objc; + // deprecated, but used for public reexport under `std::os::unix::raw`, as // well as `std::os::macos`/`std::os::ios`, because those modules precede the // decision to remove these. diff --git a/library/std/src/os/darwin/objc.rs b/library/std/src/os/darwin/objc.rs new file mode 100644 index 00000000000..a4b31fee7c5 --- /dev/null +++ b/library/std/src/os/darwin/objc.rs @@ -0,0 +1,13 @@ +//! Defines types and macros for Objective-C interoperability. +//! +//! This module re-exports all the items in [`core::os::darwin::objc`]. +//! +//! [`core::os::darwin::objc`]: ../../../../core/os/darwin/objc/index.html "mod core::os::darwin::objc" + +#![unstable(feature = "darwin_objc", issue = "145496")] + +// We can't generate an intra-doc link for this automatically since `core::os::darwin` isn't +// compiled into `core` on every platform even though it's documented on every platform. +// We just link to it directly in the module documentation above instead. +#[cfg(not(doc))] +pub use core::os::darwin::objc::*; diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 09429af06e3..5b7b5a8ea80 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -406,8 +406,10 @@ pub trait ChildExt: Sealed { /// use libc::SIGTERM; /// /// fn main() -> io::Result<()> { + /// # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) { /// let child = Command::new("cat").stdin(Stdio::piped()).spawn()?; /// child.send_signal(SIGTERM)?; + /// # } /// Ok(()) /// } /// ``` diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs index 345d5b74285..20e5383dc09 100644 --- a/library/std/src/os/windows/ffi.rs +++ b/library/std/src/os/windows/ffi.rs @@ -141,7 +141,7 @@ impl OsStrExt for OsStr { pub struct EncodeWide<'a> { inner: alloc::wtf8::EncodeWide<'a>, } -#[stable(feature = "encode_wide_debug", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "encode_wide_debug", since = "1.91.0")] impl fmt::Debug for EncodeWide<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner, f) diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 5e8d2f8e78e..1997785885d 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -122,7 +122,7 @@ impl<'a> PanicHookInfo<'a> { /// ``` #[must_use] #[inline] - #[stable(feature = "panic_payload_as_str", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "panic_payload_as_str", since = "1.91.0")] pub fn payload_as_str(&self) -> Option<&str> { if let Some(s) = self.payload.downcast_ref::<&str>() { Some(s) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8b7282c51d1..b7be869c4eb 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -331,7 +331,7 @@ fn default_hook(info: &PanicHookInfo<'_>) { #[cfg(not(test))] #[doc(hidden)] -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { /// A reason for forcing an immediate abort on panic. @@ -371,7 +371,7 @@ pub mod panic_count { #[cfg(not(test))] #[doc(hidden)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { use crate::cell::Cell; @@ -499,13 +499,13 @@ pub mod panic_count { pub use realstd::rt::panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> { Ok(f()) } /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> { union Data<F, R> { f: ManuallyDrop<F>, @@ -720,14 +720,14 @@ pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] #[cfg_attr(not(any(test, doctest)), lang = "begin_panic")] // lang item for CTFE panic support -// never inline unless panic_immediate_abort to avoid code +// never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval pub const fn begin_panic<M: Any + Send>(msg: M) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { intrinsics::abort() } @@ -861,7 +861,7 @@ fn panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(panic = "immediate-abort", inline)] pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { panic_count::increase(false); @@ -890,16 +890,14 @@ pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { /// on which to slap yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { - unsafe { - crate::intrinsics::abort(); - } + crate::intrinsics::abort(); } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 70ba502d684..718c7c2e3b1 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1191,7 +1191,7 @@ impl PathBuf { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[inline] - #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "1.91.0")] pub const fn new() -> PathBuf { PathBuf { inner: OsString::new() } } @@ -1594,7 +1594,7 @@ impl PathBuf { /// p.add_extension(""); /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); /// ``` - #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "path_add_extension", since = "1.91.0")] pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool { self._add_extension(extension.as_ref()) } @@ -2103,35 +2103,35 @@ impl PartialEq for PathBuf { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<str> for PathBuf { #[inline] fn eq(&self, other: &str) -> bool { - Path::eq(self, other) + self.as_path() == other } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<PathBuf> for str { #[inline] fn eq(&self, other: &PathBuf) -> bool { - other == self + self == other.as_path() } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<String> for PathBuf { #[inline] fn eq(&self, other: &String) -> bool { - **self == **other + self.as_path() == other.as_str() } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<PathBuf> for String { #[inline] fn eq(&self, other: &PathBuf) -> bool { - other == self + self.as_str() == other.as_path() } } @@ -2724,7 +2724,7 @@ impl Path { /// /// [`Path::file_stem`]: Path::file_stem /// - #[stable(feature = "path_file_prefix", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "path_file_prefix", since = "1.91.0")] #[must_use] pub fn file_prefix(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before)) @@ -2888,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")); /// ``` - #[stable(feature = "path_add_extension", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "path_add_extension", since = "1.91.0")] 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); @@ -3405,7 +3405,7 @@ impl PartialEq for Path { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<str> for Path { #[inline] fn eq(&self, other: &str) -> bool { @@ -3414,7 +3414,7 @@ impl cmp::PartialEq<str> for Path { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<Path> for str { #[inline] fn eq(&self, other: &Path) -> bool { @@ -3422,19 +3422,19 @@ impl cmp::PartialEq<Path> for str { } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<String> for Path { #[inline] fn eq(&self, other: &String) -> bool { - self == &*other + self == other.as_str() } } -#[stable(feature = "eq_str_for_path", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "eq_str_for_path", since = "1.91.0")] impl cmp::PartialEq<Path> for String { #[inline] fn eq(&self, other: &Path) -> bool { - other == self + self.as_str() == other } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 48265de90c4..5c0ac526a36 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -268,8 +268,8 @@ impl AsInner<imp::Process> for Child { } } -impl FromInner<(imp::Process, imp::StdioPipes)> for Child { - fn from_inner((handle, io): (imp::Process, imp::StdioPipes)) -> Child { +impl FromInner<(imp::Process, StdioPipes)> for Child { + fn from_inner((handle, io): (imp::Process, StdioPipes)) -> Child { Child { handle, stdin: io.stdin.map(ChildStdin::from_inner), @@ -296,6 +296,15 @@ impl fmt::Debug for Child { } } +/// The pipes connected to a spawned process. +/// +/// Used to pass pipe handles between this module and [`imp`]. +pub(crate) struct StdioPipes { + pub stdin: Option<AnonPipe>, + pub stdout: Option<AnonPipe>, + pub stderr: Option<AnonPipe>, +} + /// A handle to a child process's standard input (stdin). /// /// This struct is used in the [`stdin`] field on [`Child`]. @@ -532,6 +541,7 @@ impl fmt::Debug for ChildStderr { /// to be changed (for example, by adding arguments) prior to spawning: /// /// ``` +/// # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) { /// use std::process::Command; /// /// let output = if cfg!(target_os = "windows") { @@ -548,6 +558,7 @@ impl fmt::Debug for ChildStderr { /// }; /// /// let hello = output.stdout; +/// # } /// ``` /// /// `Command` can be reused to spawn multiple processes. The builder methods @@ -1348,7 +1359,7 @@ impl Output { /// /// ``` /// #![feature(exit_status_error)] - /// # #[cfg(all(unix, not(target_os = "android")))] { + /// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] { /// use std::process::Command; /// assert!(Command::new("false").output().unwrap().exit_ok().is_err()); /// # } @@ -1695,7 +1706,7 @@ impl From<io::Stdout> for Stdio { /// # Ok(()) /// # } /// # - /// # if cfg!(all(unix, not(target_os = "android"))) { + /// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { /// # test().unwrap(); /// # } /// ``` @@ -1724,7 +1735,7 @@ impl From<io::Stderr> for Stdio { /// # Ok(()) /// # } /// # - /// # if cfg!(all(unix, not(target_os = "android"))) { + /// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { /// # test().unwrap(); /// # } /// ``` @@ -1800,7 +1811,7 @@ impl ExitStatus { /// /// ``` /// #![feature(exit_status_error)] - /// # if cfg!(unix) { + /// # if cfg!(all(unix, not(all(target_vendor = "apple", not(target_os = "macos"))))) { /// use std::process::Command; /// /// let status = Command::new("ls") @@ -1907,7 +1918,7 @@ impl crate::sealed::Sealed for ExitStatusError {} /// /// ``` /// #![feature(exit_status_error)] -/// # if cfg!(all(unix, not(target_os = "android"))) { +/// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { /// use std::process::{Command, ExitStatusError}; /// /// fn run(cmd: &str) -> Result<(), ExitStatusError> { @@ -1950,7 +1961,7 @@ impl ExitStatusError { /// /// ``` /// #![feature(exit_status_error)] - /// # #[cfg(all(unix, not(target_os = "android")))] { + /// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] { /// use std::process::Command; /// /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err(); @@ -1975,7 +1986,7 @@ impl ExitStatusError { /// ``` /// #![feature(exit_status_error)] /// - /// # if cfg!(all(unix, not(target_os = "android"))) { + /// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { /// use std::num::NonZero; /// use std::process::Command; /// diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 5879914ca20..12c5130defe 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -5,7 +5,15 @@ use crate::mem::MaybeUninit; use crate::str; fn known_command() -> Command { - if cfg!(windows) { Command::new("help") } else { Command::new("echo") } + if cfg!(windows) { + Command::new("help") + } else if cfg!(all(target_vendor = "apple", not(target_os = "macos"))) { + // iOS/tvOS/watchOS/visionOS have a very limited set of commandline + // binaries available. + Command::new("log") + } else { + Command::new("echo") + } } #[cfg(target_os = "android")] @@ -19,7 +27,10 @@ fn shell_cmd() -> Command { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn smoke() { let p = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "exit 0"]).spawn() @@ -41,7 +52,10 @@ fn smoke_failure() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn exit_reported_right() { let p = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "exit 1"]).spawn() @@ -56,7 +70,10 @@ fn exit_reported_right() { #[test] #[cfg(unix)] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn signal_reported_right() { use crate::os::unix::process::ExitStatusExt; @@ -80,7 +97,10 @@ pub fn run_output(mut cmd: Command) -> String { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn stdout_works() { if cfg!(target_os = "windows") { let mut cmd = Command::new("cmd"); @@ -94,7 +114,11 @@ fn stdout_works() { } #[test] -#[cfg_attr(any(windows, target_os = "vxworks"), ignore)] +#[cfg_attr(windows, ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn set_current_dir_works() { // On many Unix platforms this will use the posix_spawn path. let mut cmd = shell_cmd(); @@ -116,7 +140,11 @@ fn set_current_dir_works() { } #[test] -#[cfg_attr(any(windows, target_os = "vxworks"), ignore)] +#[cfg_attr(windows, ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn stdin_works() { let mut p = shell_cmd() .arg("-c") @@ -134,7 +162,10 @@ fn stdin_works() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn child_stdout_read_buf() { let mut cmd = if cfg!(target_os = "windows") { let mut cmd = Command::new("cmd"); @@ -165,7 +196,10 @@ fn child_stdout_read_buf() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_process_status() { let mut status = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() @@ -191,7 +225,10 @@ fn test_process_output_fail_to_start() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_process_output_output() { let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() @@ -206,7 +243,10 @@ fn test_process_output_output() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_process_output_error() { let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() @@ -221,7 +261,10 @@ fn test_process_output_error() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_finish_once() { let mut prog = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() @@ -232,7 +275,10 @@ fn test_finish_once() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_finish_twice() { let mut prog = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() @@ -244,7 +290,10 @@ fn test_finish_twice() { } #[test] -#[cfg_attr(any(target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_wait_with_output_once() { let prog = if cfg!(target_os = "windows") { Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() @@ -279,7 +328,10 @@ pub fn env_cmd() -> Command { } #[test] -#[cfg_attr(target_os = "vxworks", ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_override_env() { use crate::env; @@ -302,7 +354,10 @@ fn test_override_env() { } #[test] -#[cfg_attr(target_os = "vxworks", ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_add_to_env() { let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); let output = String::from_utf8_lossy(&result.stdout).to_string(); @@ -314,7 +369,10 @@ fn test_add_to_env() { } #[test] -#[cfg_attr(target_os = "vxworks", ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no shell available" +)] fn test_capture_env_at_spawn() { use crate::env; @@ -378,7 +436,10 @@ fn test_interior_nul_in_current_dir_is_error() { // Regression tests for #30862. #[test] -#[cfg_attr(target_os = "vxworks", ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no `env` cmd available" +)] fn test_interior_nul_in_env_key_is_error() { match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), @@ -387,7 +448,10 @@ fn test_interior_nul_in_env_key_is_error() { } #[test] -#[cfg_attr(target_os = "vxworks", ignore)] +#[cfg_attr( + any(target_os = "vxworks", all(target_vendor = "apple", not(target_os = "macos"))), + ignore = "no `env` cmd available" +)] fn test_interior_nul_in_env_value_is_error() { match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index b3f3b301e3d..2717b7b469c 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -39,11 +39,11 @@ fn __rust_abort() { // - nothing (so this macro is a no-op) macro_rules! rtprintpanic { ($($t:tt)*) => { - #[cfg(not(feature = "panic_immediate_abort"))] + #[cfg(not(panic = "immediate-abort"))] if let Some(mut out) = crate::sys::stdio::panic_output() { let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); } - #[cfg(feature = "panic_immediate_abort")] + #[cfg(panic = "immediate-abort")] { let _ = format_args!($($t)*); } @@ -161,7 +161,7 @@ fn lang_start_internal( // mechanism itself. // // There are a couple of instances where unwinding can begin. First is inside of the - // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a + // `rt::init`, `rt::cleanup` and similar functions controlled by std. In those instances a // panic is a std implementation bug. A quite likely one too, as there isn't any way to // prevent std from accidentally introducing a panic to these functions. Another is from // user code from `main` or, more nefariously, as described in e.g. issue #86030. diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index 07430ce3a13..eeecf5d7107 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -373,7 +373,7 @@ impl<T: ?Sized> Mutex<T> { /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] // #[unstable(feature = "nonpoison_mutex", issue = "134645")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs index eb0aef99cc1..b2f26edc083 100644 --- a/library/std/src/sync/nonpoison/rwlock.rs +++ b/library/std/src/sync/nonpoison/rwlock.rs @@ -495,7 +495,7 @@ impl<T: ?Sized> RwLock<T> { /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 7e9d920d92f..6fdb4f6799e 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -668,7 +668,7 @@ impl<T: ?Sized> Mutex<T> { /// are properly synchronized to avoid data races, and that it is not read /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 0a463f3f9c7..e3a72c73bf4 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -667,7 +667,7 @@ impl<T: ?Sized> RwLock<T> { /// are properly synchronized to avoid data races, and that it is not read /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *mut T { + pub const fn data_ptr(&self) -> *mut T { self.data.get() } } diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 4140718560c..f560b616dd9 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -355,7 +355,7 @@ impl<T: ?Sized> ReentrantLock<T> { /// properly synchronized to avoid data races, and that it is not read /// through after the lock is dropped. #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")] - pub fn data_ptr(&self) -> *const T { + pub const fn data_ptr(&self) -> *const T { &raw const self.data } diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index 6d4b09494a3..2045b2fecc6 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -92,6 +92,9 @@ cfg_select! { target_os = "uefi" => { mod uefi; } + target_os = "vexos" => { + mod vexos; + } target_family = "wasm" => { mod wasm; } diff --git a/library/std/src/sys/alloc/vexos.rs b/library/std/src/sys/alloc/vexos.rs new file mode 100644 index 00000000000..c1fb6896a89 --- /dev/null +++ b/library/std/src/sys/alloc/vexos.rs @@ -0,0 +1,96 @@ +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#![allow(static_mut_refs)] + +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sync::atomic::{AtomicBool, Ordering}; + +// Symbols for heap section boundaries defined in the target's linkerscript +unsafe extern "C" { + static mut __heap_start: u8; + static mut __heap_end: u8; +} + +static mut DLMALLOC: dlmalloc::Dlmalloc<Vexos> = dlmalloc::Dlmalloc::new_with_allocator(Vexos); + +struct Vexos; + +unsafe impl dlmalloc::Allocator for Vexos { + /// Allocs system resources + fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) { + static INIT: AtomicBool = AtomicBool::new(false); + + if !INIT.swap(true, Ordering::Relaxed) { + // This target has no growable heap, as user memory has a fixed + // size/location and VEXos does not manage allocation for us. + unsafe { + ( + (&raw mut __heap_start).cast::<u8>(), + (&raw const __heap_end).offset_from_unsigned(&raw const __heap_start), + 0, + ) + } + } else { + (ptr::null_mut(), 0, 0) + } + } + + fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 { + ptr::null_mut() + } + + fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool { + false + } + + fn free(&self, _ptr: *mut u8, _size: usize) -> bool { + return false; + } + + fn can_release_part(&self, _flags: u32) -> bool { + false + } + + fn allocates_zeros(&self) -> bool { + false + } + + fn page_size(&self) -> usize { + 0x1000 + } +} + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling malloc() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.malloc(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling calloc() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.calloc(layout.size(), layout.align()) } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling free() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // SAFETY: DLMALLOC access is guaranteed to be safe because we are a single-threaded target, which + // guarantees unique and non-reentrant access to the allocator. As such, no allocator lock is used. + // Calling realloc() is safe because preconditions on this function match the trait method preconditions. + unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } + } +} diff --git a/library/std/src/sys/args/zkvm.rs b/library/std/src/sys/args/zkvm.rs index 194ba7159d4..d26bf1eaff9 100644 --- a/library/std/src/sys/args/zkvm.rs +++ b/library/std/src/sys/args/zkvm.rs @@ -1,25 +1,20 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::sys::os_str; +use crate::ffi::{OsStr, OsString}; +use crate::num::NonZero; +use crate::sync::OnceLock; use crate::sys::pal::{WORD_SIZE, abi}; -use crate::sys_common::FromInner; - -pub struct Args { - i_forward: usize, - i_back: usize, - count: usize, -} +use crate::{fmt, ptr, slice}; pub fn args() -> Args { - let count = unsafe { abi::sys_argc() }; - Args { i_forward: 0, i_back: 0, count } + Args { iter: ARGS.get_or_init(|| get_args()).iter() } } -impl Args { - /// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc - /// and will not return if the index is out of bounds. - fn argv(i: usize) -> OsString { - let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) }; +fn get_args() -> Vec<&'static OsStr> { + let argc = unsafe { abi::sys_argc() }; + let mut args = Vec::with_capacity(argc); + + for i in 0..argc { + // Get the size of the argument then the data. + let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) }; let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE; let words = unsafe { abi::sys_alloc_words(arg_len_words) }; @@ -27,20 +22,24 @@ impl Args { let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) }; debug_assert_eq!(arg_len, arg_len2); - // Convert to OsString. - // - // FIXME: We can probably get rid of the extra copy here if we - // reimplement "os_str" instead of just using the generic unix - // "os_str". - let arg_bytes: &[u8] = - unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) }; - OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() }) + let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) }; + args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) }); } + args } +static ARGS: OnceLock<Vec<&'static OsStr>> = OnceLock::new(); + +pub struct Args { + iter: slice::Iter<'static, &'static OsStr>, +} + +impl !Send for Args {} +impl !Sync for Args {} + impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().finish() + self.iter.as_slice().fmt(f) } } @@ -48,34 +47,48 @@ impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option<OsString> { - if self.i_forward >= self.count - self.i_back { - None - } else { - let arg = Self::argv(self.i_forward); - self.i_forward += 1; - Some(arg) - } + self.iter.next().map(|arg| arg.to_os_string()) } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - (self.count, Some(self.count)) + self.iter.size_hint() } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.count + #[inline] + fn count(self) -> usize { + self.iter.len() + } + + fn last(self) -> Option<OsString> { + self.iter.last().map(|arg| arg.to_os_string()) + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { + self.iter.advance_by(n) } } impl DoubleEndedIterator for Args { fn next_back(&mut self) -> Option<OsString> { - if self.i_back >= self.count - self.i_forward { - None - } else { - let arg = Self::argv(self.count - 1 - self.i_back); - self.i_back += 1; - Some(arg) - } + self.iter.next_back().map(|arg| arg.to_os_string()) + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() } } diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs index 9683fd47cf9..573f540483b 100644 --- a/library/std/src/sys/env_consts.rs +++ b/library/std/src/sys/env_consts.rs @@ -2,7 +2,7 @@ // Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates. // This ensures that they must be mutually exclusive and do not have precedence -// like cfg_if!. +// like cfg_select!. macro cfg_unordered( $(#[cfg($cfg:meta)] $os:item)* #[else] $fallback:item @@ -323,6 +323,17 @@ pub mod os { pub const EXE_EXTENSION: &str = "efi"; } +#[cfg(target_os = "vexos")] +pub mod os { + pub const FAMILY: &str = ""; + pub const OS: &str = "vexos"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ".bin"; + pub const EXE_EXTENSION: &str = "bin"; +} + #[cfg(target_os = "visionos")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 0276bf6e64c..64f5a6b36d3 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -35,6 +35,10 @@ cfg_select! { mod uefi; use uefi as imp; } + target_os = "vexos" => { + mod vexos; + use vexos as imp; + } target_os = "wasi" => { mod wasi; use wasi as imp; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index dfd6ce56a76..33a1e7ff5e4 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -21,29 +21,31 @@ use libc::fstatat as fstatat64; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::fstatat64; #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "solaris", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", target_os = "illumos", - target_os = "aix", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", all(target_os = "linux", target_env = "musl"), ))] use libc::readdir as readdir64; #[cfg(not(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "l4re", - target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", )))] use libc::readdir_r as readdir64_r; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] @@ -271,16 +273,17 @@ unsafe impl Send for Dir {} unsafe impl Sync for Dir {} #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", ))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -295,16 +298,17 @@ pub struct DirEntry { // we're not using the immediate `d_name` on these targets. Keeping this as an // `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere. #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", ))] struct dirent64_min { d_ino: u64, @@ -319,16 +323,17 @@ struct dirent64_min { } #[cfg(not(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", )))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -698,16 +703,17 @@ impl Iterator for ReadDir { type Item = io::Result<DirEntry>; #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", + target_os = "hurd", target_os = "illumos", - target_os = "aix", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", ))] fn next(&mut self) -> Option<io::Result<DirEntry>> { use crate::sys::os::{errno, set_errno}; @@ -768,6 +774,9 @@ impl Iterator for ReadDir { // only access those bytes. #[cfg(not(target_os = "vita"))] let entry = dirent64_min { + #[cfg(target_os = "freebsd")] + d_ino: (*entry_ptr).d_fileno, + #[cfg(not(target_os = "freebsd"))] d_ino: (*entry_ptr).d_ino as u64, #[cfg(not(any( target_os = "solaris", @@ -791,16 +800,17 @@ impl Iterator for ReadDir { } #[cfg(not(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", + target_os = "hurd", target_os = "illumos", - target_os = "aix", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", )))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { @@ -970,36 +980,32 @@ impl DirEntry { } #[cfg(any( - target_os = "linux", + target_os = "aix", + target_os = "android", target_os = "cygwin", target_os = "emscripten", - target_os = "android", - target_os = "solaris", - target_os = "illumos", - target_os = "haiku", - target_os = "l4re", - target_os = "fuchsia", - target_os = "redox", - target_os = "vxworks", target_os = "espidf", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", target_os = "horizon", - target_os = "vita", - target_os = "aix", - target_os = "nto", target_os = "hurd", + target_os = "illumos", + target_os = "l4re", + target_os = "linux", + target_os = "nto", + target_os = "redox", target_os = "rtems", + target_os = "solaris", + target_os = "vita", + target_os = "vxworks", target_vendor = "apple", ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } - #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly" - ))] + #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly"))] pub fn ino(&self) -> u64 { self.entry.d_fileno as u64 } @@ -1014,7 +1020,6 @@ impl DirEntry { #[cfg(any( target_os = "netbsd", target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple", ))] @@ -1030,7 +1035,6 @@ impl DirEntry { #[cfg(not(any( target_os = "netbsd", target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple", )))] @@ -1040,6 +1044,7 @@ impl DirEntry { #[cfg(not(any( target_os = "android", + target_os = "freebsd", target_os = "linux", target_os = "solaris", target_os = "illumos", @@ -1055,6 +1060,7 @@ impl DirEntry { } #[cfg(any( target_os = "android", + target_os = "freebsd", target_os = "linux", target_os = "solaris", target_os = "illumos", diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs new file mode 100644 index 00000000000..f642e7cb074 --- /dev/null +++ b/library/std/src/sys/fs/vexos.rs @@ -0,0 +1,615 @@ +use crate::ffi::{OsString, c_char}; +use crate::fmt; +use crate::fs::TryLockError; +use crate::hash::Hash; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::path::{Path, PathBuf}; +use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::time::SystemTime; +use crate::sys::{unsupported, unsupported_err}; + +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_fs; +pub use unsupported_fs::{ + DirBuilder, FileTimes, canonicalize, link, readlink, remove_dir_all, rename, rmdir, symlink, + unlink, +}; + +/// VEXos file descriptor. +/// +/// This stores an opaque pointer to a [FatFs file object structure] managed by VEXos +/// representing an open file on disk. +/// +/// [FatFs file object structure]: https://github.com/Xilinx/embeddedsw/blob/master/lib/sw_services/xilffs/src/include/ff.h?rgh-link-date=2025-09-23T20%3A03%3A43Z#L215 +/// +/// # Safety +/// +/// Since this platform uses a pointer to to an internal filesystem structure with a lifetime +/// associated with it (rather than a UNIX-style file descriptor table), care must be taken to +/// ensure that the pointer held by `FileDesc` is valid for as long as it exists. +#[derive(Debug)] +struct FileDesc(*mut vex_sdk::FIL); + +// SAFETY: VEXos's FDs can be used on a thread other than the one they were created on. +unsafe impl Send for FileDesc {} +// SAFETY: We assume an environment without threads (i.e. no RTOS). +// (If there were threads, it is possible that a mutex would be required.) +unsafe impl Sync for FileDesc {} + +pub struct File { + fd: FileDesc, +} + +#[derive(Clone)] +pub enum FileAttr { + Dir, + File { size: u64 }, +} + +pub struct ReadDir(!); + +pub struct DirEntry { + path: PathBuf, +} + +#[derive(Clone, Debug)] +pub struct OpenOptions { + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions {} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct FileType { + is_dir: bool, +} + +impl FileAttr { + pub fn size(&self) -> u64 { + match self { + Self::File { size } => *size, + Self::Dir => 0, + } + } + + pub fn perm(&self) -> FilePermissions { + FilePermissions {} + } + + pub fn file_type(&self) -> FileType { + FileType { is_dir: matches!(self, FileAttr::Dir) } + } + + pub fn modified(&self) -> io::Result<SystemTime> { + unsupported() + } + + pub fn accessed(&self) -> io::Result<SystemTime> { + unsupported() + } + + pub fn created(&self) -> io::Result<SystemTime> { + unsupported() + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + false + } + + pub fn set_readonly(&mut self, _readonly: bool) { + panic!("Perimissions do not exist") + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.is_dir + } + + pub fn is_file(&self) -> bool { + !self.is_dir + } + + pub fn is_symlink(&self) -> bool { + // No symlinks in VEXos - entries are either files or directories. + false + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl Iterator for ReadDir { + type Item = io::Result<DirEntry>; + + fn next(&mut self) -> Option<io::Result<DirEntry>> { + self.0 + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.path.clone() + } + + pub fn file_name(&self) -> OsString { + self.path.file_name().unwrap_or_default().into() + } + + pub fn metadata(&self) -> io::Result<FileAttr> { + stat(&self.path) + } + + pub fn file_type(&self) -> io::Result<FileType> { + Ok(self.metadata()?.file_type()) + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + } + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + pub fn write(&mut self, write: bool) { + self.write = write; + } + pub fn append(&mut self, append: bool) { + self.append = append; + } + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + pub fn create(&mut self, create: bool) { + self.create = create; + } + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { + run_path_with_cstr(path, &|path| { + // Enforce the invariants of `create_new`/`create`. + // + // Since VEXos doesn't have anything akin to POSIX's `oflags`, we need to enforce + // the requirements that `create_new` can't have an existing file and `!create` + // doesn't create a file ourselves. + if !opts.read && (opts.write || opts.append) && (opts.create_new || !opts.create) { + let status = unsafe { vex_sdk::vexFileStatus(path.as_ptr()) }; + + if opts.create_new && status != 0 { + return Err(io::const_error!(io::ErrorKind::AlreadyExists, "file exists",)); + } else if !opts.create && status == 0 { + return Err(io::const_error!( + io::ErrorKind::NotFound, + "no such file or directory", + )); + } + } + + let file = match opts { + // read + write - unsupported + OpenOptions { read: true, write: true, .. } => { + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "opening files with read and write access is unsupported on this target", + )); + } + + // read + OpenOptions { + read: true, + write: false, + append: _, + truncate: false, + create: false, + create_new: false, + } => unsafe { vex_sdk::vexFileOpen(path.as_ptr(), c"".as_ptr()) }, + + // append + OpenOptions { + read: false, + write: _, + append: true, + truncate: false, + create: _, + create_new: _, + } => unsafe { vex_sdk::vexFileOpenWrite(path.as_ptr()) }, + + // write + OpenOptions { + read: false, + write: true, + append: false, + truncate, + create: _, + create_new: _, + } => unsafe { + if *truncate { + vex_sdk::vexFileOpenCreate(path.as_ptr()) + } else { + // Open in append, but jump to the start of the file. + let fd = vex_sdk::vexFileOpenWrite(path.as_ptr()); + vex_sdk::vexFileSeek(fd, 0, 0); + fd + } + }, + + _ => { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid argument")); + } + }; + + if file.is_null() { + Err(io::const_error!(io::ErrorKind::NotFound, "could not open file")) + } else { + Ok(Self { fd: FileDesc(file) }) + } + }) + } + + pub fn file_attr(&self) -> io::Result<FileAttr> { + // `vexFileSize` returns -1 upon error, so u64::try_from will fail on error. + if let Ok(size) = u64::try_from(unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileSize(self.fd.0) + }) { + Ok(FileAttr::File { size }) + } else { + Err(io::const_error!(io::ErrorKind::InvalidData, "failed to get file size")) + } + } + + pub fn fsync(&self) -> io::Result<()> { + self.flush() + } + + pub fn datasync(&self) -> io::Result<()> { + self.flush() + } + + pub fn lock(&self) -> io::Result<()> { + unsupported() + } + + pub fn lock_shared(&self) -> io::Result<()> { + unsupported() + } + + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) + } + + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) + } + + pub fn unlock(&self) -> io::Result<()> { + unsupported() + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + unsupported() + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + let len = buf.len() as u32; + let buf_ptr = buf.as_mut_ptr(); + let read = unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileRead(buf_ptr.cast::<c_char>(), 1, len, self.fd.0) + }; + + if read < 0 { + Err(io::const_error!(io::ErrorKind::Other, "could not read from file")) + } else { + Ok(read as usize) + } + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + crate::io::default_read_vectored(|b| self.read(b), bufs) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|b| self.read(b), cursor) + } + + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { + let len = buf.len() as u32; + let buf_ptr = buf.as_ptr(); + let written = unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileWrite(buf_ptr.cast_mut().cast::<c_char>(), 1, len, self.fd.0) + }; + + if written < 0 { + Err(io::const_error!(io::ErrorKind::Other, "could not write to file")) + } else { + Ok(written as usize) + } + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + crate::io::default_write_vectored(|b| self.write(b), bufs) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn flush(&self) -> io::Result<()> { + unsafe { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + vex_sdk::vexFileSync(self.fd.0); + } + Ok(()) + } + + pub fn tell(&self) -> io::Result<u64> { + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + let position = unsafe { vex_sdk::vexFileTell(self.fd.0) }; + + position.try_into().map_err(|_| { + io::const_error!(io::ErrorKind::InvalidData, "failed to get current location in file") + }) + } + + pub fn size(&self) -> Option<io::Result<u64>> { + None + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { + const SEEK_SET: i32 = 0; + const SEEK_CUR: i32 = 1; + const SEEK_END: i32 = 2; + + fn try_convert_offset<T: TryInto<u32>>(offset: T) -> io::Result<u32> { + offset.try_into().map_err(|_| { + io::const_error!( + io::ErrorKind::InvalidInput, + "cannot seek to an offset too large to fit in a 32 bit integer", + ) + }) + } + + // SAFETY: `self.fd` contains a valid pointer to `FIL` for this struct's lifetime. + match pos { + SeekFrom::Start(offset) => unsafe { + map_fresult(vex_sdk::vexFileSeek(self.fd.0, try_convert_offset(offset)?, SEEK_SET))? + }, + SeekFrom::End(offset) => unsafe { + if offset >= 0 { + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_END, + ))? + } else { + // `vexFileSeek` does not support seeking with negative offset, meaning + // we have to calculate the offset from the end of the file ourselves. + + // Seek to the end of the file to get the end position in the open buffer. + map_fresult(vex_sdk::vexFileSeek(self.fd.0, 0, SEEK_END))?; + let end_position = self.tell()?; + + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + // NOTE: Files internally use a 32-bit representation for stream + // position, so `end_position as i64` should never overflow. + try_convert_offset(end_position as i64 + offset)?, + SEEK_SET, + ))? + } + }, + SeekFrom::Current(offset) => unsafe { + if offset >= 0 { + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset(offset)?, + SEEK_CUR, + ))? + } else { + // `vexFileSeek` does not support seeking with negative offset, meaning + // we have to calculate the offset from the stream position ourselves. + map_fresult(vex_sdk::vexFileSeek( + self.fd.0, + try_convert_offset((self.tell()? as i64) + offset)?, + SEEK_SET, + ))? + } + }, + } + + Ok(self.tell()?) + } + + pub fn duplicate(&self) -> io::Result<File> { + unsupported() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + unsupported() + } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + unsupported() + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File").field("fd", &self.fd.0).finish() + } +} +impl Drop for File { + fn drop(&mut self) { + unsafe { vex_sdk::vexFileClose(self.fd.0) }; + } +} + +pub fn readdir(_p: &Path) -> io::Result<ReadDir> { + // While there *is* a userspace function for reading file directories, + // the necessary implementation cannot currently be done cleanly, as + // VEXos does not expose directory length to user programs. + // + // This means that we would need to create a large fixed-length buffer + // and hope that the folder's contents didn't exceed that buffer's length, + // which obviously isn't behavior we want to rely on in the standard library. + unsupported() +} + +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + unsupported() +} + +pub fn exists(path: &Path) -> io::Result<bool> { + run_path_with_cstr(path, &|path| Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0)) +} + +pub fn stat(p: &Path) -> io::Result<FileAttr> { + // `vexFileStatus` returns 3 if the given path is a directory, 1 if the path is a + // file, or 0 if no such path exists. + const FILE_STATUS_DIR: u32 = 3; + + run_path_with_cstr(p, &|c_path| { + let file_type = unsafe { vex_sdk::vexFileStatus(c_path.as_ptr()) }; + + // We can't get the size if its a directory because we cant open it as a file + if file_type == FILE_STATUS_DIR { + Ok(FileAttr::Dir) + } else { + let mut opts = OpenOptions::new(); + opts.read(true); + let file = File::open(p, &opts)?; + file.file_attr() + } + }) +} + +pub fn lstat(p: &Path) -> io::Result<FileAttr> { + // Symlinks aren't supported in this filesystem + stat(p) +} + +// Cannot use `copy` from `common` here, since `File::set_permissions` is unsupported on this target. +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + use crate::fs::File; + + // NOTE: If `from` is a directory, this call should fail due to vexFileOpen* returning null. + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} + +fn map_fresult(fresult: vex_sdk::FRESULT) -> io::Result<()> { + // VEX uses a derivative of FatFs (Xilinx's xilffs library) for filesystem operations. + match fresult { + vex_sdk::FRESULT::FR_OK => Ok(()), + vex_sdk::FRESULT::FR_DISK_ERR => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "internal function reported an unrecoverable hard error", + )), + vex_sdk::FRESULT::FR_INT_ERR => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "internal error in filesystem runtime", + )), + vex_sdk::FRESULT::FR_NOT_READY => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "the storage device could not be prepared to work", + )), + vex_sdk::FRESULT::FR_NO_FILE => Err(io::const_error!( + io::ErrorKind::NotFound, + "could not find the file in the directory" + )), + vex_sdk::FRESULT::FR_NO_PATH => Err(io::const_error!( + io::ErrorKind::NotFound, + "a directory in the path name could not be found", + )), + vex_sdk::FRESULT::FR_INVALID_NAME => Err(io::const_error!( + io::ErrorKind::InvalidInput, + "the given string is invalid as a path name", + )), + vex_sdk::FRESULT::FR_DENIED => Err(io::const_error!( + io::ErrorKind::PermissionDenied, + "the required access for this operation was denied", + )), + vex_sdk::FRESULT::FR_EXIST => Err(io::const_error!( + io::ErrorKind::AlreadyExists, + "an object with the same name already exists in the directory", + )), + vex_sdk::FRESULT::FR_INVALID_OBJECT => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "invalid or null file/directory object", + )), + vex_sdk::FRESULT::FR_WRITE_PROTECTED => Err(io::const_error!( + io::ErrorKind::PermissionDenied, + "a write operation was performed on write-protected media", + )), + vex_sdk::FRESULT::FR_INVALID_DRIVE => Err(io::const_error!( + io::ErrorKind::InvalidInput, + "an invalid drive number was specified in the path name", + )), + vex_sdk::FRESULT::FR_NOT_ENABLED => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "work area for the logical drive has not been registered", + )), + vex_sdk::FRESULT::FR_NO_FILESYSTEM => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "valid FAT volume could not be found on the drive", + )), + vex_sdk::FRESULT::FR_MKFS_ABORTED => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "failed to create filesystem volume" + )), + vex_sdk::FRESULT::FR_TIMEOUT => Err(io::const_error!( + io::ErrorKind::TimedOut, + "the function was canceled due to a timeout of thread-safe control", + )), + vex_sdk::FRESULT::FR_LOCKED => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "the operation to the object was rejected by file sharing control", + )), + vex_sdk::FRESULT::FR_NOT_ENOUGH_CORE => { + Err(io::const_error!(io::ErrorKind::OutOfMemory, "not enough memory for the operation")) + } + vex_sdk::FRESULT::FR_TOO_MANY_OPEN_FILES => Err(io::const_error!( + io::ErrorKind::Uncategorized, + "maximum number of open files has been reached", + )), + vex_sdk::FRESULT::FR_INVALID_PARAMETER => { + Err(io::const_error!(io::ErrorKind::InvalidInput, "a given parameter was invalid")) + } + _ => unreachable!(), // C-style enum + } +} diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index b65d86de12a..0b65b9cb389 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -848,7 +848,14 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { // Iterate over all the entries in this directory, and travel recursively if // necessary - for entry in ReadDir::new(fd, dummy_root) { + // + // Note that all directory entries for this directory are read first before + // any removal is done. This works around the fact that the WASIp1 API for + // reading directories is not well-designed for handling mutations between + // invocations of reading a directory. By reading all the entries at once + // this ensures that, at least without concurrent modifications, it should + // be possible to delete everything. + for entry in ReadDir::new(fd, dummy_root).collect::<Vec<_>>() { let entry = entry?; let path = crate::str::from_utf8(&entry.name).map_err(|_| { io::const_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 9b54571997d..8c9c17d3f17 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -499,16 +499,6 @@ impl fmt::Display for NonIpSockAddr { pub struct LookupHost(!); -impl LookupHost { - fn new(host: String) -> io::Result<LookupHost> { - Err(io::Error::new(io::ErrorKind::Uncategorized, NonIpSockAddr { host })) - } - - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option<SocketAddr> { @@ -516,18 +506,9 @@ impl Iterator for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(v: &str) -> io::Result<LookupHost> { - LookupHost::new(v.to_owned()) - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> { - LookupHost::new(format!("{host}:{port}")) - } +pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> { + Err(io::Error::new( + io::ErrorKind::Uncategorized, + NonIpSockAddr { host: format!("{host}:{port}") }, + )) } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 564f2e3a01f..1dd06e97bba 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -258,7 +258,7 @@ fn to_ipv6mr_interface(value: u32) -> crate::ffi::c_uint { } //////////////////////////////////////////////////////////////////////////////// -// get_host_addresses +// lookup_host //////////////////////////////////////////////////////////////////////////////// pub struct LookupHost { @@ -267,12 +267,6 @@ pub struct LookupHost { port: u16, } -impl LookupHost { - pub fn port(&self) -> u16 { - self.port - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option<SocketAddr> { @@ -281,7 +275,10 @@ impl Iterator for LookupHost { let cur = self.cur.as_ref()?; self.cur = cur.ai_next; match socket_addr_from_c(cur.ai_addr.cast(), cur.ai_addrlen as usize) { - Ok(addr) => return Some(addr), + Ok(mut addr) => { + addr.set_port(self.port); + return Some(addr); + } Err(_) => continue, } } @@ -298,42 +295,17 @@ impl Drop for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(s: &str) -> io::Result<LookupHost> { - macro_rules! try_opt { - ($e:expr, $msg:expr) => { - match $e { - Some(r) => r, - None => return Err(io::const_error!(io::ErrorKind::InvalidInput, $msg)), - } - }; +pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> { + init(); + run_with_cstr(host.as_bytes(), &|c_host| { + let mut hints: c::addrinfo = unsafe { mem::zeroed() }; + hints.ai_socktype = c::SOCK_STREAM; + let mut res = ptr::null_mut(); + unsafe { + cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) + .map(|_| LookupHost { original: res, cur: res, port }) } - - // split the string by ':' and convert the second part to u16 - let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); - let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - (host, port).try_into() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> { - init(); - - run_with_cstr(host.as_bytes(), &|c_host| { - let mut hints: c::addrinfo = unsafe { mem::zeroed() }; - hints.ai_socktype = c::SOCK_STREAM; - let mut res = ptr::null_mut(); - unsafe { - cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) - .map(|_| LookupHost { original: res, cur: res, port }) - } - }) - } + }) } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/net/connection/socket/tests.rs b/library/std/src/sys/net/connection/socket/tests.rs index fc236b8027b..049355afca7 100644 --- a/library/std/src/sys/net/connection/socket/tests.rs +++ b/library/std/src/sys/net/connection/socket/tests.rs @@ -4,7 +4,7 @@ use crate::collections::HashMap; #[test] fn no_lookup_host_duplicates() { let mut addrs = HashMap::new(); - let lh = match LookupHost::try_from(("localhost", 0)) { + let lh = match lookup_host("localhost", 0) { Ok(lh) => lh, Err(e) => panic!("couldn't resolve `localhost`: {e}"), }; diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 00368042873..004f6d413a1 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -333,12 +333,6 @@ impl fmt::Debug for UdpSocket { pub struct LookupHost(!); -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option<SocketAddr> { @@ -346,18 +340,6 @@ impl Iterator for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result<LookupHost> { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> { - unsupported() - } +pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> { + unsupported() } diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index fbc86343272..fb18e8dec55 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -304,12 +304,6 @@ impl fmt::Debug for UdpSocket { pub struct LookupHost(!); -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option<SocketAddr> { @@ -317,18 +311,6 @@ impl Iterator for LookupHost { } } -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &str) -> io::Result<LookupHost> { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> { - unsupported() - } +pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> { + unsupported() } diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index cdfa25c8a44..048dafdcd7f 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -477,12 +477,6 @@ impl fmt::Debug for UdpSocket { pub struct LookupHost(!); -impl LookupHost { - pub fn port(&self) -> u16 { - self.0 - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option<SocketAddr> { @@ -490,18 +484,6 @@ impl Iterator for LookupHost { } } -impl<'a> TryFrom<&'a str> for LookupHost { - type Error = io::Error; - - fn try_from(_v: &'a str) -> io::Result<LookupHost> { - unsupported() - } -} - -impl<'a> TryFrom<(&'a str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> { - unsupported() - } +pub fn lookup_host(_host: &str, _port: u16) -> io::Result<LookupHost> { + unsupported() } diff --git a/library/std/src/sys/net/connection/xous/dns.rs b/library/std/src/sys/net/connection/xous/dns.rs index bb29d211fad..b139376f597 100644 --- a/library/std/src/sys/net/connection/xous/dns.rs +++ b/library/std/src/sys/net/connection/xous/dns.rs @@ -1,15 +1,8 @@ -use core::convert::{TryFrom, TryInto}; - use crate::io; use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::os::xous::ffi::lend_mut; use crate::os::xous::services::{DnsLendMut, dns_server}; -pub struct DnsError { - #[allow(dead_code)] - pub code: u8, -} - #[repr(C, align(4096))] struct LookupHostQuery([u8; 4096]); @@ -20,12 +13,6 @@ pub struct LookupHost { count: usize, } -impl LookupHost { - pub fn port(&self) -> u16 { - self.port - } -} - impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option<SocketAddr> { @@ -72,7 +59,7 @@ impl Iterator for LookupHost { } } -pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> { +pub fn lookup_host(query: &str, port: u16) -> io::Result<LookupHost> { let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port }; // Copy the query into the message that gets sent to the DNS server @@ -89,7 +76,7 @@ pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> { ) .unwrap(); if result.data.0[0] != 0 { - return Err(DnsError { code: result.data.0[1] }); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "DNS failure")); } assert_eq!(result.offset, 0); result.count = result.data.0[1] as usize; @@ -98,31 +85,3 @@ pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> { result.offset = 2; Ok(result) } - -impl TryFrom<&str> for LookupHost { - type Error = io::Error; - - fn try_from(s: &str) -> io::Result<LookupHost> { - macro_rules! try_opt { - ($e:expr, $msg:expr) => { - match $e { - Some(r) => r, - None => return Err(io::const_error!(io::ErrorKind::InvalidInput, &$msg)), - } - }; - } - - // split the string by ':' and convert the second part to u16 - let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); - let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - (host, port).try_into() - } -} - -impl TryFrom<(&str, u16)> for LookupHost { - type Error = io::Error; - - fn try_from(v: (&str, u16)) -> io::Result<LookupHost> { - lookup(v.0, v.1).map_err(|_e| io::const_error!(io::ErrorKind::InvalidInput, "DNS failure")) - } -} diff --git a/library/std/src/sys/net/connection/xous/mod.rs b/library/std/src/sys/net/connection/xous/mod.rs index e44a375b9e3..0f77be5c3fa 100644 --- a/library/std/src/sys/net/connection/xous/mod.rs +++ b/library/std/src/sys/net/connection/xous/mod.rs @@ -45,4 +45,4 @@ pub struct GetAddress { raw: [u8; 4096], } -pub use dns::LookupHost; +pub use dns::lookup_host; diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index f76a5f96c87..bd6fd5a3de4 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -26,15 +26,22 @@ impl Timespec { } fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { + fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { + debug_assert!(a >= b); + a.wrapping_sub(b).cast_unsigned() + } + if self >= other { + // Logic here is identical to Unix version of `Timestamp::sub_timespec`, + // check comments there why operations do not overflow. Ok(if self.t.tv_nsec >= other.t.tv_nsec { Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, + sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec), (self.t.tv_nsec - other.t.tv_nsec) as u32, ) } else { Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, + sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec), (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, ) }) diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 513121c6d30..dd5e83ee570 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -45,6 +45,10 @@ cfg_select! { mod trusty; pub use self::trusty::*; } + target_os = "vexos" => { + mod vexos; + pub use self::vexos::*; + } all(target_os = "wasi", target_env = "p2") => { mod wasip2; pub use self::wasip2::*; diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index 275f6062463..cf0c098f8a2 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -7,8 +7,6 @@ mod common; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/thread.rs"] -pub mod thread; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index b50574de937..c0d69c3e002 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -92,6 +92,9 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff /// /// Queries a handle to determine if it supports a specified protocol. If the protocol is /// supported by the handle, it opens the protocol on behalf of the calling agent. +/// +/// The protocol is opened with the attribute GET_PROTOCOL, which means the caller is not required +/// to close the protocol interface with `EFI_BOOT_SERVICES.CloseProtocol()` pub(crate) fn open_protocol<T>( handle: NonNull<crate::ffi::c_void>, mut protocol_guid: Guid, @@ -473,6 +476,7 @@ impl<'a> crate::fmt::Debug for DevicePathNode<'a> { } } +/// Protocols installed by Rust side on a handle. pub(crate) struct OwnedProtocol<T> { guid: r_efi::efi::Guid, handle: NonNull<crate::ffi::c_void>, diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0d2100d66bc..51463eef5b7 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -72,7 +72,7 @@ mod imp { use crate::sync::OnceLock; use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering}; use crate::sys::pal::unix::os; - use crate::{io, mem, panic, ptr}; + use crate::{io, mem, ptr}; // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages // (unmapped pages) at the end of every thread's stack, so if a thread ends diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index bd7f74fea6a..c207f41cad4 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -134,28 +134,25 @@ impl Timespec { } pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { + // When a >= b, the difference fits in u64. + fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { + debug_assert!(a >= b); + a.wrapping_sub(b).cast_unsigned() + } + if self >= other { - // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM - // to optimize it into a branchless form (see also #75545): - // - // 1. `self.tv_sec - other.tv_sec` shows up as a common expression - // in both branches, i.e. the `else` must have its `- 1` - // subtraction after the common one, not interleaved with it - // (it used to be `self.tv_sec - 1 - other.tv_sec`) - // - // 2. the `Duration::new` call (or any other additional complexity) - // is outside of the `if`-`else`, not duplicated in both branches - // - // Ideally this code could be rearranged such that it more - // directly expresses the lower-cost behavior we want from it. let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() { ( - (self.tv_sec - other.tv_sec) as u64, + sub_ge_to_unsigned(self.tv_sec, other.tv_sec), self.tv_nsec.as_inner() - other.tv_nsec.as_inner(), ) } else { + // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow. + debug_assert!(self.tv_nsec < other.tv_nsec); + debug_assert!(self.tv_sec > other.tv_sec); + debug_assert!(self.tv_sec > i64::MIN); ( - (self.tv_sec - other.tv_sec - 1) as u64, + sub_ge_to_unsigned(self.tv_sec - 1, other.tv_sec), self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(), ) }; diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index 5e3295b1331..e64bbc7c616 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -2,7 +2,6 @@ pub mod os; pub mod pipe; -pub mod thread; pub mod time; mod common; diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs new file mode 100644 index 00000000000..61a34b0f68a --- /dev/null +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -0,0 +1,80 @@ +#[path = "../unsupported/os.rs"] +pub mod os; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +pub mod time; + +#[expect(dead_code)] +#[path = "../unsupported/common.rs"] +mod unsupported_common; + +pub use unsupported_common::{ + decode_error_kind, init, is_interrupted, unsupported, unsupported_err, +}; + +use crate::arch::global_asm; +use crate::ptr; +use crate::sys::stdio; +use crate::time::{Duration, Instant}; + +global_asm!( + r#" + .section .boot, "ax" + .global _boot + + _boot: + ldr sp, =__stack_top @ Set up the user stack. + b _start @ Jump to the Rust entrypoint. + "# +); + +#[cfg(not(test))] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn _start() -> ! { + unsafe extern "C" { + static mut __bss_start: u8; + static mut __bss_end: u8; + + fn main() -> i32; + } + + // Clear the .bss (uninitialized statics) section by filling it with zeroes. + // This is required, since the compiler assumes it will be zeroed on first access. + ptr::write_bytes( + &raw mut __bss_start, + 0, + (&raw mut __bss_end).offset_from_unsigned(&raw mut __bss_start), + ); + + main(); + + cleanup(); + abort_internal() +} + +// SAFETY: must be called only once during runtime cleanup. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub unsafe fn cleanup() { + let exit_time = Instant::now(); + const FLUSH_TIMEOUT: Duration = Duration::from_millis(15); + + // Force the serial buffer to flush + while exit_time.elapsed() < FLUSH_TIMEOUT { + vex_sdk::vexTasksRun(); + + // If the buffer has been fully flushed, exit the loop + if vex_sdk::vexSerialWriteFree(stdio::STDIO_CHANNEL) == (stdio::STDOUT_BUF_SIZE as i32) { + break; + } + } +} + +pub fn abort_internal() -> ! { + unsafe { + vex_sdk::vexSystemExitRequest(); + + loop { + vex_sdk::vexTasksRun(); + } + } +} diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs new file mode 100644 index 00000000000..f95d96cd27a --- /dev/null +++ b/library/std/src/sys/pal/vexos/time.rs @@ -0,0 +1,28 @@ +use crate::time::Duration; + +#[expect(dead_code)] +#[path = "../unsupported/time.rs"] +mod unsupported_time; +pub use unsupported_time::{SystemTime, UNIX_EPOCH}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(Duration); + +impl Instant { + pub fn now() -> Instant { + let micros = unsafe { vex_sdk::vexSystemHighResTimeGet() }; + Self(Duration::from_micros(micros)) + } + + 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)?)) + } +} diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index e1efa240685..9069c8d12fa 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -14,8 +14,6 @@ pub mod abi; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/thread.rs"] -pub mod thread; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs index 9ef5496e57a..a1ed0cd2cdd 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -24,7 +24,7 @@ mod env; pub use env::CommandEnvs; pub use imp::{ - Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes, + Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, }; #[cfg(any( diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 4864c586988..11c8b682bb9 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -6,6 +6,7 @@ pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; use crate::num::{NonZero, NonZeroI32}; use crate::path::Path; +use crate::process::StdioPipes; use crate::sys::fs::File; use crate::sys::pal::helpers; use crate::sys::pal::os::error_string; @@ -27,14 +28,6 @@ pub struct Command { env: CommandEnv, } -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - #[derive(Copy, Clone, Debug)] pub enum Stdio { Inherit, diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index ea45b08e90a..1d5909e99ba 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -9,6 +9,7 @@ use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::Path; +use crate::process::StdioPipes; use crate::sys::fd::FileDesc; use crate::sys::fs::File; #[cfg(not(target_os = "fuchsia"))] @@ -104,14 +105,6 @@ pub struct Command { setsid: bool, } -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - // passed to do_exec() with configuration of what the child stdio should look // like #[cfg_attr(target_os = "vita", allow(dead_code))] diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs index d71be510b6a..3fae5ec1468 100644 --- a/library/std/src/sys/process/unix/fuchsia.rs +++ b/library/std/src/sys/process/unix/fuchsia.rs @@ -2,6 +2,7 @@ use libc::{c_int, size_t}; use super::common::*; use crate::num::NonZero; +use crate::process::StdioPipes; use crate::sys::pal::fuchsia::*; use crate::{fmt, io, mem, ptr}; diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs index b4cf060fba9..cda1bf74f1c 100644 --- a/library/std/src/sys/process/unix/mod.rs +++ b/library/std/src/sys/process/unix/mod.rs @@ -23,5 +23,5 @@ cfg_select! { pub use imp::{ExitStatus, ExitStatusError, Process}; -pub use self::common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; +pub use self::common::{Command, CommandArgs, ExitCode, Stdio}; pub use crate::ffi::OsString as EnvKey; diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 11d48878727..7d944f2f7ee 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -13,6 +13,7 @@ use libc::{gid_t, uid_t}; use super::common::*; use crate::io::{self, Error, ErrorKind}; use crate::num::NonZero; +use crate::process::StdioPipes; use crate::sys::cvt; #[cfg(target_os = "linux")] use crate::sys::pal::linux::pidfd::PidFd; diff --git a/library/std/src/sys/process/unix/unix/tests.rs b/library/std/src/sys/process/unix/unix/tests.rs index f4d6ac6b4e3..663ba61f966 100644 --- a/library/std/src/sys/process/unix/unix/tests.rs +++ b/library/std/src/sys/process/unix/unix/tests.rs @@ -51,6 +51,7 @@ fn exitstatus_display_tests() { #[test] #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "tvos", target_os = "watchos"), ignore = "fork is prohibited")] fn test_command_fork_no_unwind() { let got = catch_unwind(|| { let mut c = Command::new("echo"); diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs index 87403cd50f8..9bda394f246 100644 --- a/library/std/src/sys/process/unix/unsupported.rs +++ b/library/std/src/sys/process/unix/unsupported.rs @@ -3,6 +3,7 @@ use libc::{c_int, pid_t}; use super::common::*; use crate::io; use crate::num::NonZero; +use crate::process::StdioPipes; use crate::sys::pal::unsupported::*; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index 2275cbb946a..346ca6d74c9 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -4,8 +4,8 @@ use libc::{self, RTP_ID, c_char, c_int}; use super::common::*; use crate::io::{self, ErrorKind}; use crate::num::NonZero; -use crate::sys::cvt; -use crate::sys::pal::thread; +use crate::process::StdioPipes; +use crate::sys::{cvt, thread}; use crate::{fmt, sys}; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs index 469922c78ac..636465b68e5 100644 --- a/library/std/src/sys/process/unsupported.rs +++ b/library/std/src/sys/process/unsupported.rs @@ -3,6 +3,7 @@ pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::path::Path; +use crate::process::StdioPipes; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; @@ -23,14 +24,6 @@ pub struct Command { stderr: Option<Stdio>, } -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - #[derive(Debug)] pub enum Stdio { Inherit, diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index f9e15b82475..1f2001bdc20 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -15,6 +15,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; use crate::os::windows::process::ProcThreadAttributeList; use crate::path::{Path, PathBuf}; +use crate::process::StdioPipes; use crate::sync::Mutex; use crate::sys::args::{self, Arg}; use crate::sys::c::{self, EXIT_FAILURE, EXIT_SUCCESS}; @@ -169,12 +170,6 @@ pub enum Stdio { Handle(Handle), } -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - impl Command { pub fn new(program: &OsStr) -> Command { Command { diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 1e0eec07b50..3c5a4c82a9f 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -101,6 +101,7 @@ cfg_select! { any( all(target_family = "wasm", target_os = "unknown"), target_os = "xous", + target_os = "vexos", ) => { // FIXME: finally remove std support for wasm32-unknown-unknown // FIXME: add random data generation to xous @@ -116,6 +117,7 @@ cfg_select! { all(target_family = "wasm", target_os = "unknown"), all(target_os = "wasi", target_env = "p2"), target_os = "xous", + target_os = "vexos", )))] pub fn hashmap_random_keys() -> (u64, u64) { let mut buf = [0; 16]; diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index 7436e4d9de4..404ac877926 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -29,6 +29,10 @@ cfg_select! { mod uefi; pub use uefi::*; } + target_os = "vexos" => { + mod vexos; + pub use vexos::*; + } all(target_os = "wasi", target_env = "p1") => { mod wasip1; pub use wasip1::*; diff --git a/library/std/src/sys/stdio/vexos.rs b/library/std/src/sys/stdio/vexos.rs new file mode 100644 index 00000000000..9a391feb7a8 --- /dev/null +++ b/library/std/src/sys/stdio/vexos.rs @@ -0,0 +1,100 @@ +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub type Stderr = Stdout; + +pub const STDIO_CHANNEL: u32 = 1; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let mut count = 0; + + for out_byte in buf.iter_mut() { + let byte = unsafe { vex_sdk::vexSerialReadChar(STDIO_CHANNEL) }; + if byte < 0 { + break; + } + + *out_byte = byte as u8; + count += 1; + } + + Ok(count) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let mut written = 0; + + // HACK: VEXos holds an internal ringbuffer for serial writes that is flushed to USB1 + // roughly every millisecond by `vexTasksRun`. For writes larger than 2048 bytes, we + // must block until that buffer is flushed to USB1 before writing the rest of `buf`. + // + // This is fairly nonstandard for a `write` implementation, but it avoids a guaranteed + // recursive panic when using macros such as `print!` to write large amounts of data + // (buf.len() > 2048) to stdout at once. + for chunk in buf.chunks(STDOUT_BUF_SIZE) { + if unsafe { vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize } < chunk.len() { + self.flush().unwrap(); + } + + let count: usize = unsafe { + vex_sdk::vexSerialWriteBuffer(STDIO_CHANNEL, chunk.as_ptr(), chunk.len() as u32) + } + .try_into() + .map_err(|_| { + io::const_error!(io::ErrorKind::Uncategorized, "internal write error occurred") + })?; + + written += count; + + // This is a sanity check to ensure that we don't end up with non-contiguous + // buffer writes. e.g. a chunk gets only partially written, but we continue + // attempting to write the remaining chunks. + // + // In practice, this should never really occur since the previous flush ensures + // enough space in FIFO to write the entire chunk to vexSerialWriteBuffer. + if count != chunk.len() { + break; + } + } + + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + // This may block for up to a millisecond. + unsafe { + while (vex_sdk::vexSerialWriteFree(STDIO_CHANNEL) as usize) != STDOUT_BUF_SIZE { + vex_sdk::vexTasksRun(); + } + } + + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 4096; +pub const STDOUT_BUF_SIZE: usize = 2048; + +pub fn is_ebadf(_err: &io::Error) -> bool { + false +} + +pub fn panic_output() -> Option<impl io::Write> { + Some(Stdout::new()) +} diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 6bb7fc1a20e..3bd83dd760a 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -81,6 +81,13 @@ cfg_select! { ))] pub use unsupported::set_name; } + target_os = "vexos" => { + mod vexos; + pub use vexos::{sleep, yield_now}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE}; + } all(target_os = "wasi", target_env = "p1") => { mod wasip1; pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now}; diff --git a/library/std/src/sys/thread/vexos.rs b/library/std/src/sys/thread/vexos.rs new file mode 100644 index 00000000000..d917dde4d0b --- /dev/null +++ b/library/std/src/sys/thread/vexos.rs @@ -0,0 +1,17 @@ +use crate::time::{Duration, Instant}; + +pub fn yield_now() { + unsafe { + vex_sdk::vexTasksRun(); + } +} + +pub fn sleep(dur: Duration) { + let start = Instant::now(); + + while start.elapsed() < dur { + unsafe { + vex_sdk::vexTasksRun(); + } + } +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index cff74857c47..d5c795093cf 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -29,6 +29,7 @@ cfg_select! { target_os = "uefi", target_os = "zkvm", target_os = "trusty", + target_os = "vexos", ) => { mod no_threads; pub use no_threads::{EagerStorage, LazyStorage, thread_local_inner}; @@ -98,6 +99,7 @@ pub(crate) mod guard { target_os = "uefi", target_os = "zkvm", target_os = "trusty", + target_os = "vexos", ) => { pub(crate) fn enable() { // FIXME: Right now there is no concept of "thread exit" on diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 797feeb2bbb..0a6f2e5d508 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -230,7 +230,7 @@ impl fmt::Display for AccessError { impl Error for AccessError {} // This ensures the panicking code is outlined from `with` for `LocalKey`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] fn panic_access_error(err: AccessError) -> ! { diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index fa76c50597b..837a14b808f 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -2528,7 +2528,17 @@ fn normalize_lexically() { } #[test] -/// See issue#146183 -fn compare_path_to_str() { - assert!(&PathBuf::from("x") == "x"); +/// See issue#146183 and issue#146940 +fn compare_path_like_to_str_like() { + let path_buf = PathBuf::from("x"); + let path = Path::new("x"); + let s = String::from("x"); + assert!(path == "x"); + assert!("x" == path); + assert!(path == &s); + assert!(&s == path); + assert!(&path_buf == "x"); + assert!("x" == &path_buf); + assert!(path_buf == s); + assert!(s == path_buf); } diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs index 43b45cb2d2b..93f73ccad3e 100644 --- a/library/std/tests/process_spawning.rs +++ b/library/std/tests/process_spawning.rs @@ -7,6 +7,7 @@ mod common; #[test] // Process spawning not supported by Miri, Emscripten and wasi #[cfg_attr(any(miri, target_os = "emscripten", target_os = "wasi"), ignore)] +#[cfg_attr(any(target_os = "tvos", target_os = "watchos"), ignore = "fork is prohibited")] fn issue_15149() { // If we're the parent, copy our own binary to a new directory. let my_path = env::current_exe().unwrap(); diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index 40709eae37c..be1948af915 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -227,3 +227,19 @@ fn big_math() { check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub); check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub); } + +#[test] +#[cfg(unix)] +fn system_time_duration_since_max_range_on_unix() { + // Repro regression https://github.com/rust-lang/rust/issues/146228 + + // Min and max values of `SystemTime` on Unix. + let min = SystemTime::UNIX_EPOCH - (Duration::new(i64::MAX as u64 + 1, 0)); + let max = SystemTime::UNIX_EPOCH + (Duration::new(i64::MAX as u64, 999_999_999)); + + let delta_a = max.duration_since(min).expect("duration_since overflow"); + let delta_b = min.duration_since(max).expect_err("duration_since overflow").duration(); + + assert_eq!(Duration::MAX, delta_a); + assert_eq!(Duration::MAX, delta_b); +} |
