diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d11b511 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "backtrace-rs"] + path = backtrace-rs + url = https://github.com/rust-lang/backtrace-rs.git +[submodule "crates/std/crates/backtrace-rs"] + path = crates/std/crates/backtrace-rs + url = https://github.com/rust-lang/backtrace-rs.git diff --git a/Cargo.toml b/Cargo.toml index 6895294..b52f444 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "3" -members = ["crates/bytes-struct","crates/io","crates/std", "crates/shared", "user/*"] +members = ["crates/bytes-struct","crates/io", "crates/shared", "user/*"] +exclude = ["crates/std/crates/backtrace-rs"] [package] name = "kernel-rust" diff --git a/crates/bffs/src/lib.rs b/crates/bffs/src/lib.rs index ba52fb0..1bd1a59 100644 --- a/crates/bffs/src/lib.rs +++ b/crates/bffs/src/lib.rs @@ -1,4 +1,5 @@ #![feature(iterator_try_collect, iter_order_by)] +#![allow(unused_features)] #![cfg_attr(any(not(feature = "std"), target_arch = "riscv64"), no_std)] use core::cell::RefCell; diff --git a/crates/std/Cargo.toml b/crates/std/Cargo.toml index 4c67fc0..48742d1 100644 --- a/crates/std/Cargo.toml +++ b/crates/std/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] -backtrace_rs = { package = "backtrace", version = "0.3", default-features = false } +cfg-if = { version = "1.0" } +rustc-demangle = { version = "0.1.27" } hashbrown = "0.16" os-std-macros = { path = "../os-std-macros" } shared = { path = "../shared", features = ["user"] } diff --git a/crates/std/crates/backtrace-rs b/crates/std/crates/backtrace-rs new file mode 160000 index 0000000..28ec93b --- /dev/null +++ b/crates/std/crates/backtrace-rs @@ -0,0 +1 @@ +Subproject commit 28ec93b503bf0410745bc3d571bf3dc1caac3019 diff --git a/crates/std/justfile b/crates/std/justfile index 5656b24..c21f302 100644 --- a/crates/std/justfile +++ b/crates/std/justfile @@ -28,17 +28,29 @@ cp_std path: setup-std: @# Not copied : sys/mod.rs, io.rs, error.rs, thread.rs, sync.rs - # @just cp_std "process.rs" - # @just cp_std "fs.rs" # @just cp_std "collections/mod.rs" + @just cp_std "alloc.rs" + @just cp_std "ascii.rs" + @just cp_std "backtrace.rs" + @just cp_std "bstr.rs" @just cp_std "env.rs" + @just cp_std "error.rs" + @just cp_std "fs.rs" + @just cp_std "keyword_docs.rs" + @just cp_std "macros.rs" + @just cp_std "panic.rs" + @just cp_std "panicking.rs" + @just cp_std "pat.rs" + @just cp_std "path.rs" + @just cp_std "process.rs" + @just cp_std "random.rs" + @just cp_std "rt.rs" + # @just cp_std "tests_helpers.rs" @just cp_std "time.rs" + @just cp_std "os/mod.rs" @just cp_std "os/raw/mod.rs" @just cp_std "os/raw/tests.rs" - @just cp_std "bstr.rs" - @just cp_std "panicking.rs" - @just cp_std "panic.rs" @just cp_std "collections/hash/map.rs" @just cp_std "collections/hash/set.rs" @just cp_std "collections/hash/mod.rs" @@ -114,6 +126,7 @@ setup-std: @just cp_std "sys/cmath.rs" @just cp_std "sys/process/mod.rs" @just cp_std "sys/process/env.rs" + @just cp_std "sys/process/unsupported.rs" @just cp_std "sys/args/mod.rs" @just cp_std "sys/args/unsupported.rs" @just cp_std "sys/pal/mod.rs" @@ -162,7 +175,10 @@ setup-std: @just cp_std "sys/stdio/unsupported.rs" @just cp_std "sys/alloc/mod.rs" @just cp_std "sys/backtrace.rs" - @just cp_std "alloc.rs" + @just cp_std "sys/fs/mod.rs" + @just cp_std "sys/fs/unsupported.rs" + @just cp_std "sys/helpers/mod.rs" + @just cp_std "sys/helpers/small_c_string.rs" + @just cp_std "sys/helpers/tests.rs" + @just cp_std "sys/helpers/wstr.rs" @# Copied but edited for the moment - # @just cp_std "sys/process/unsupported.rs" - # @just cp_std "path.rs" diff --git a/crates/std/patches.sed b/crates/std/patches.sed index 1913a3e..00d3677 100644 --- a/crates/std/patches.sed +++ b/crates/std/patches.sed @@ -1,5 +1,4 @@ s|crate::collections::TryReserveError|alloc_crate::collections::TryReserveError|g -s|crate::sync::Arc|alloc_crate::sync::Arc|g s|alloc::ffi|alloc_crate::ffi|g s|alloc::slice::Join|alloc_crate::slice::Join|g s|alloc::bstr|alloc_crate::bstr|g diff --git a/crates/std/src/ascii.rs b/crates/std/src/ascii.rs new file mode 100644 index 0000000..3813f32 --- /dev/null +++ b/crates/std/src/ascii.rs @@ -0,0 +1,210 @@ +//! Operations on ASCII strings and characters. +//! +//! Most string operations in Rust act on UTF-8 strings. However, at times it +//! makes more sense to only consider the ASCII character set for a specific +//! operation. +//! +//! The [`AsciiExt`] trait provides methods that allow for character +//! operations that only act on the ASCII subset and leave non-ASCII characters +//! alone. +//! +//! The [`escape_default`] function provides an iterator over the bytes of an +//! escaped version of the character given. + +#![stable(feature = "rust1", since = "1.0.0")] + +#[unstable(feature = "ascii_char", issue = "110998")] +pub use core::ascii::Char; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::ascii::{EscapeDefault, escape_default}; + +/// Extension methods for ASCII-subset only operations. +/// +/// Be aware that operations on seemingly non-ASCII characters can sometimes +/// have unexpected results. Consider this example: +/// +/// ``` +/// use std::ascii::AsciiExt; +/// +/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ"); +/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé"); +/// ``` +/// +/// In the first example, the lowercased string is represented `"cafe\u{301}"` +/// (the last character is an acute accent [combining character]). Unlike the +/// other characters in the string, the combining character will not get mapped +/// to an uppercase variant, resulting in `"CAFE\u{301}"`. In the second +/// example, the lowercased string is represented `"caf\u{e9}"` (the last +/// character is a single Unicode character representing an 'e' with an acute +/// accent). Since the last character is defined outside the scope of ASCII, +/// it will not get mapped to an uppercase variant, resulting in `"CAF\u{e9}"`. +/// +/// [combining character]: https://en.wikipedia.org/wiki/Combining_character +#[stable(feature = "rust1", since = "1.0.0")] +#[deprecated(since = "1.26.0", note = "use inherent methods instead")] +pub trait AsciiExt { + /// Container type for copied ASCII characters. + #[stable(feature = "rust1", since = "1.0.0")] + type Owned; + + /// Checks if the value is within the ASCII range. + /// + /// # Note + /// + /// This method is deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. + #[stable(feature = "rust1", since = "1.0.0")] + fn is_ascii(&self) -> bool; + + /// Makes a copy of the value in its ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`make_ascii_uppercase`]. + /// + /// To uppercase ASCII characters in addition to non-ASCII characters, use + /// [`str::to_uppercase`]. + /// + /// # Note + /// + /// This method is deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// + /// [`make_ascii_uppercase`]: AsciiExt::make_ascii_uppercase + #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] + fn to_ascii_uppercase(&self) -> Self::Owned; + + /// Makes a copy of the value in its ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`make_ascii_lowercase`]. + /// + /// To lowercase ASCII characters in addition to non-ASCII characters, use + /// [`str::to_lowercase`]. + /// + /// # Note + /// + /// This method is deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// + /// [`make_ascii_lowercase`]: AsciiExt::make_ascii_lowercase + #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] + fn to_ascii_lowercase(&self) -> Self::Owned; + + /// Checks that two values are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + /// + /// # Note + /// + /// This method is deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. + #[stable(feature = "rust1", since = "1.0.0")] + fn eq_ignore_ascii_case(&self, other: &Self) -> bool; + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// # Note + /// + /// This method is deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// + /// [`to_ascii_uppercase`]: AsciiExt::to_ascii_uppercase + #[stable(feature = "ascii", since = "1.9.0")] + fn make_ascii_uppercase(&mut self); + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// # Note + /// + /// This method is deprecated in favor of the identically-named + /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// + /// [`to_ascii_lowercase`]: AsciiExt::to_ascii_lowercase + #[stable(feature = "ascii", since = "1.9.0")] + fn make_ascii_lowercase(&mut self); +} + +macro_rules! delegating_ascii_methods { + () => { + #[inline] + fn is_ascii(&self) -> bool { + self.is_ascii() + } + + #[inline] + fn to_ascii_uppercase(&self) -> Self::Owned { + self.to_ascii_uppercase() + } + + #[inline] + fn to_ascii_lowercase(&self) -> Self::Owned { + self.to_ascii_lowercase() + } + + #[inline] + fn eq_ignore_ascii_case(&self, o: &Self) -> bool { + self.eq_ignore_ascii_case(o) + } + + #[inline] + fn make_ascii_uppercase(&mut self) { + self.make_ascii_uppercase(); + } + + #[inline] + fn make_ascii_lowercase(&mut self) { + self.make_ascii_lowercase(); + } + }; +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl AsciiExt for u8 { + type Owned = u8; + + delegating_ascii_methods!(); +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl AsciiExt for char { + type Owned = char; + + delegating_ascii_methods!(); +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl AsciiExt for [u8] { + type Owned = Vec; + + delegating_ascii_methods!(); +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl AsciiExt for str { + type Owned = String; + + delegating_ascii_methods!(); +} diff --git a/crates/std/src/backtrace.rs b/crates/std/src/backtrace.rs new file mode 100644 index 0000000..99724e2 --- /dev/null +++ b/crates/std/src/backtrace.rs @@ -0,0 +1,478 @@ +//! Support for capturing a stack backtrace of an OS thread +//! +//! This module contains the support necessary to capture a stack backtrace of a +//! running OS thread from the OS thread itself. The `Backtrace` type supports +//! capturing a stack trace via the `Backtrace::capture` and +//! `Backtrace::force_capture` functions. +//! +//! A backtrace is typically quite handy to attach to errors (e.g. types +//! implementing `std::error::Error`) to get a causal chain of where an error +//! was generated. +//! +//! ## Accuracy +//! +//! Backtraces are attempted to be as accurate as possible, but no guarantees +//! are provided about the exact accuracy of a backtrace. Instruction pointers, +//! symbol names, filenames, line numbers, etc, may all be incorrect when +//! reported. Accuracy is attempted on a best-effort basis, however, any bug +//! reports are always welcome to indicate areas of improvement! +//! +//! For most platforms a backtrace with a filename/line number requires that +//! programs be compiled with debug information. Without debug information +//! filenames/line numbers will not be reported. +//! +//! ## Platform support +//! +//! Not all platforms that std compiles for support capturing backtraces. Some +//! platforms simply do nothing when capturing a backtrace. To check whether the +//! platform supports capturing backtraces you can consult the `BacktraceStatus` +//! enum as a result of `Backtrace::status`. +//! +//! Like above with accuracy platform support is done on a best effort basis. +//! Sometimes libraries might not be available at runtime or something may go +//! wrong which would cause a backtrace to not be captured. Please feel free to +//! report issues with platforms where a backtrace cannot be captured though! +//! +//! ## Environment Variables +//! +//! The `Backtrace::capture` function might not actually capture a backtrace by +//! default. Its behavior is governed by two environment variables: +//! +//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture` +//! will never capture a backtrace. Any other value set will enable +//! `Backtrace::capture`. +//! +//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable +//! is consulted with the same rules of `RUST_LIB_BACKTRACE`. +//! +//! * If neither of the above env vars are set, then `Backtrace::capture` will +//! be disabled. +//! +//! Capturing a backtrace can be a quite expensive runtime operation, so the +//! environment variables allow either forcibly disabling this runtime +//! performance hit or allow selectively enabling it in some programs. +//! +//! Note that the `Backtrace::force_capture` function can be used to ignore +//! these environment variables. Also note that the state of environment +//! variables is cached once the first backtrace is created, so altering +//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change +//! how backtraces are captured. + +#![stable(feature = "backtrace", since = "1.65.0")] + +#[cfg(test)] +mod tests; + +// NB: A note on resolution of a backtrace: +// +// Backtraces primarily happen in two steps, one is where we actually capture +// the stack backtrace, giving us a list of instruction pointers corresponding +// to stack frames. Next we take these instruction pointers and, one-by-one, +// turn them into a human readable name (like `main`). +// +// The first phase can be somewhat expensive (walking the stack), especially +// on MSVC where debug information is consulted to return inline frames each as +// their own frame. The second phase, however, is almost always extremely +// expensive (on the order of milliseconds sometimes) when it's consulting debug +// information. +// +// We attempt to amortize this cost as much as possible by delaying resolution +// of an address to a human readable name for as long as possible. When +// `Backtrace::create` is called to capture a backtrace it doesn't actually +// perform any symbol resolution, but rather we lazily resolve symbols only just +// before they're needed for printing. This way we can make capturing a +// backtrace and throwing it away much cheaper, but actually printing a +// backtrace is still basically the same cost. +// +// This strategy comes at the cost of some synchronization required inside of a +// `Backtrace`, but that's a relatively small price to pay relative to capturing +// a backtrace or actually symbolizing it. + +use crate::backtrace_rs::{self, BytesOrWideString}; +use crate::ffi::c_void; +use crate::panic::UnwindSafe; +use crate::sync::LazyLock; +use crate::sync::atomic::Ordering::Relaxed; +use crate::sync::atomic::{Atomic, AtomicU8}; +use crate::sys::backtrace::{lock, output_filename, set_image_base}; +use crate::{env, fmt}; + +/// A captured OS thread stack backtrace. +/// +/// This type represents a stack backtrace for an OS thread captured at a +/// previous point in time. In some instances the `Backtrace` type may +/// internally be empty due to configuration. For more information see +/// `Backtrace::capture`. +#[stable(feature = "backtrace", since = "1.65.0")] +#[must_use] +pub struct Backtrace { + inner: Inner, +} + +/// The current status of a backtrace, indicating whether it was captured or +/// whether it is empty for some other reason. +#[stable(feature = "backtrace", since = "1.65.0")] +#[non_exhaustive] +#[derive(Debug, PartialEq, Eq)] +pub enum BacktraceStatus { + /// Capturing a backtrace is not supported, likely because it's not + /// implemented for the current platform. + #[stable(feature = "backtrace", since = "1.65.0")] + Unsupported, + /// Capturing a backtrace has been disabled through either the + /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables. + #[stable(feature = "backtrace", since = "1.65.0")] + Disabled, + /// A backtrace has been captured and the `Backtrace` should print + /// reasonable information when rendered. + #[stable(feature = "backtrace", since = "1.65.0")] + Captured, +} + +enum Inner { + Unsupported, + Disabled, + Captured(LazyLock), +} + +struct Capture { + actual_start: usize, + frames: Vec, +} + +fn _assert_send_sync() { + fn _assert() {} + _assert::(); +} + +/// A single frame of a backtrace. +#[unstable(feature = "backtrace_frames", issue = "79676")] +pub struct BacktraceFrame { + frame: RawFrame, + symbols: Vec, +} + +#[derive(Debug)] +enum RawFrame { + Actual(backtrace_rs::Frame), + #[cfg(test)] + Fake, +} + +struct BacktraceSymbol { + name: Option>, + filename: Option, + lineno: Option, + colno: Option, +} + +enum BytesOrWide { + Bytes(Vec), + Wide(Vec), +} + +#[stable(feature = "backtrace", since = "1.65.0")] +impl fmt::Debug for Backtrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let capture = match &self.inner { + Inner::Unsupported => return fmt.write_str(""), + Inner::Disabled => return fmt.write_str(""), + Inner::Captured(c) => &**c, + }; + + let frames = &capture.frames[capture.actual_start..]; + + write!(fmt, "Backtrace ")?; + + let mut dbg = fmt.debug_list(); + + for frame in frames { + if frame.frame.ip().is_null() { + continue; + } + + dbg.entries(&frame.symbols); + } + + dbg.finish() + } +} + +#[unstable(feature = "backtrace_frames", issue = "79676")] +impl fmt::Debug for BacktraceFrame { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut dbg = fmt.debug_list(); + dbg.entries(&self.symbols); + dbg.finish() + } +} + +impl fmt::Debug for BacktraceSymbol { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + // FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280 + // FIXME: Also, include column numbers into the debug format as Display already has them. + // Until there are stable per-frame accessors, the format shouldn't be changed: + // https://github.com/rust-lang/rust/issues/65280#issuecomment-638966585 + write!(fmt, "{{ ")?; + + if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) { + write!(fmt, "fn: \"{:#}\"", fn_name)?; + } else { + write!(fmt, "fn: ")?; + } + + if let Some(fname) = self.filename.as_ref() { + write!(fmt, ", file: \"{:?}\"", fname)?; + } + + if let Some(line) = self.lineno { + write!(fmt, ", line: {:?}", line)?; + } + + write!(fmt, " }}") + } +} + +impl fmt::Debug for BytesOrWide { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + output_filename( + fmt, + match self { + BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), + BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), + }, + backtrace_rs::PrintFmt::Short, + crate::env::current_dir().as_ref().ok(), + ) + } +} + +impl Backtrace { + /// Returns whether backtrace captures are enabled through environment + /// variables. + fn enabled() -> bool { + // Cache the result of reading the environment variables to make + // backtrace captures speedy, because otherwise reading environment + // variables every time can be somewhat slow. + static ENABLED: Atomic = AtomicU8::new(0); + match ENABLED.load(Relaxed) { + 0 => {} + 1 => return false, + _ => return true, + } + let enabled = match env::var("RUST_LIB_BACKTRACE") { + Ok(s) => s != "0", + Err(_) => match env::var("RUST_BACKTRACE") { + Ok(s) => s != "0", + Err(_) => false, + }, + }; + ENABLED.store(enabled as u8 + 1, Relaxed); + enabled + } + + /// Captures a stack backtrace of the current thread. + /// + /// This function will capture a stack backtrace of the current OS thread of + /// execution, returning a `Backtrace` type which can be later used to print + /// the entire stack trace or render it to a string. + /// + /// This function will be a noop if the `RUST_BACKTRACE` or + /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either + /// environment variable is set and enabled then this function will actually + /// capture a backtrace. Capturing a backtrace can be both memory intensive + /// and slow, so these environment variables allow liberally using + /// `Backtrace::capture` and only incurring a slowdown when the environment + /// variables are set. + /// + /// To forcibly capture a backtrace regardless of environment variables, use + /// the `Backtrace::force_capture` function. + #[stable(feature = "backtrace", since = "1.65.0")] + #[inline(never)] // want to make sure there's a frame here to remove + pub fn capture() -> Backtrace { + if !Backtrace::enabled() { + return Backtrace { inner: Inner::Disabled }; + } + Backtrace::create(Backtrace::capture as fn() -> Backtrace as usize) + } + + /// Forcibly captures a full backtrace, regardless of environment variable + /// configuration. + /// + /// This function behaves the same as `capture` except that it ignores the + /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment + /// variables, always capturing a backtrace. + /// + /// Note that capturing a backtrace can be an expensive operation on some + /// platforms, so this should be used with caution in performance-sensitive + /// parts of code. + #[stable(feature = "backtrace", since = "1.65.0")] + #[inline(never)] // want to make sure there's a frame here to remove + pub fn force_capture() -> Backtrace { + Backtrace::create(Backtrace::force_capture as fn() -> Backtrace as usize) + } + + /// Forcibly captures a disabled backtrace, regardless of environment + /// variable configuration. + #[stable(feature = "backtrace", since = "1.65.0")] + #[rustc_const_stable(feature = "backtrace", since = "1.65.0")] + pub const fn disabled() -> Backtrace { + Backtrace { inner: Inner::Disabled } + } + + // Capture a backtrace which start just before the function addressed by + // `ip` + fn create(ip: usize) -> Backtrace { + let _lock = lock(); + let mut frames = Vec::new(); + let mut actual_start = None; + set_image_base(); + unsafe { + backtrace_rs::trace_unsynchronized(|frame| { + frames.push(BacktraceFrame { + frame: RawFrame::Actual(frame.clone()), + symbols: Vec::new(), + }); + if frame.symbol_address().addr() == ip && actual_start.is_none() { + actual_start = Some(frames.len()); + } + true + }); + } + + // If no frames came out assume that this is an unsupported platform + // since `backtrace` doesn't provide a way of learning this right now, + // and this should be a good enough approximation. + let inner = if frames.is_empty() { + Inner::Unsupported + } else { + Inner::Captured(LazyLock::new(lazy_resolve(Capture { + actual_start: actual_start.unwrap_or(0), + frames, + }))) + }; + + Backtrace { inner } + } + + /// Returns the status of this backtrace, indicating whether this backtrace + /// request was unsupported, disabled, or a stack trace was actually + /// captured. + #[stable(feature = "backtrace", since = "1.65.0")] + #[must_use] + pub fn status(&self) -> BacktraceStatus { + match self.inner { + Inner::Unsupported => BacktraceStatus::Unsupported, + Inner::Disabled => BacktraceStatus::Disabled, + Inner::Captured(_) => BacktraceStatus::Captured, + } + } +} + +impl<'a> Backtrace { + /// Returns an iterator over the backtrace frames. + #[must_use] + #[unstable(feature = "backtrace_frames", issue = "79676")] + pub fn frames(&'a self) -> &'a [BacktraceFrame] { + if let Inner::Captured(c) = &self.inner { &c.frames } else { &[] } + } +} + +#[stable(feature = "backtrace", since = "1.65.0")] +impl fmt::Display for Backtrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let capture = match &self.inner { + Inner::Unsupported => return fmt.write_str("unsupported backtrace"), + Inner::Disabled => return fmt.write_str("disabled backtrace"), + Inner::Captured(c) => &**c, + }; + + let full = fmt.alternate(); + let (frames, style) = if full { + (&capture.frames[..], backtrace_rs::PrintFmt::Full) + } else { + (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short) + }; + + // When printing paths we try to strip the cwd if it exists, otherwise + // we just print the path as-is. Note that we also only do this for the + // short format, because if it's full we presumably want to print + // everything. + let cwd = crate::env::current_dir(); + let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| { + output_filename(fmt, path, style, cwd.as_ref().ok()) + }; + + let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path); + f.add_context()?; + for frame in frames { + if frame.symbols.is_empty() { + f.frame().print_raw(frame.frame.ip(), None, None, None)?; + } else { + for symbol in frame.symbols.iter() { + f.frame().print_raw_with_column( + frame.frame.ip(), + symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), + symbol.filename.as_ref().map(|b| match b { + BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), + BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), + }), + symbol.lineno, + symbol.colno, + )?; + } + } + } + f.finish()?; + Ok(()) + } +} + +mod helper { + use super::*; + pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; + + #[define_opaque(LazyResolve)] + pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve { + move || { + // Use the global backtrace lock to synchronize this as it's a + // requirement of the `backtrace` crate, and then actually resolve + // everything. + let _lock = lock(); + for frame in capture.frames.iter_mut() { + let symbols = &mut frame.symbols; + let frame = match &frame.frame { + RawFrame::Actual(frame) => frame, + #[cfg(test)] + RawFrame::Fake => unimplemented!(), + }; + unsafe { + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + symbols.push(BacktraceSymbol { + name: symbol.name().map(|m| m.as_bytes().to_vec()), + filename: symbol.filename_raw().map(|b| match b { + BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), + BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), + }), + lineno: symbol.lineno(), + colno: symbol.colno(), + }); + }); + } + } + + capture + } + } +} +use helper::*; + +impl RawFrame { + fn ip(&self) -> *mut c_void { + match self { + RawFrame::Actual(frame) => frame.ip(), + #[cfg(test)] + RawFrame::Fake => crate::ptr::without_provenance_mut(1), + } + } +} diff --git a/crates/std/src/collections/hash/map.rs b/crates/std/src/collections/hash/map.rs index b82beb3..fe49660 100644 --- a/crates/std/src/collections/hash/map.rs +++ b/crates/std/src/collections/hash/map.rs @@ -357,6 +357,7 @@ impl HashMap { /// map.insert(1, 2); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hash_builder: S) -> HashMap { @@ -389,6 +390,7 @@ impl HashMap { /// map.insert(1, 2); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap { HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) } @@ -409,6 +411,7 @@ impl HashMap { /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the `HashMap` to be useful, see its documentation for details. #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) } @@ -430,6 +433,7 @@ impl HashMap { /// the `HashMap` to be useful, see its documentation for details. /// #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) } diff --git a/crates/std/src/collections/hash/set.rs b/crates/std/src/collections/hash/set.rs index 6d6479f..2d41ef0 100644 --- a/crates/std/src/collections/hash/set.rs +++ b/crates/std/src/collections/hash/set.rs @@ -229,6 +229,7 @@ impl HashSet { /// set.insert(2); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hasher: S) -> HashSet { @@ -261,6 +262,7 @@ impl HashSet { /// set.insert(1); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } @@ -281,6 +283,7 @@ impl HashSet { /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the `HashSet` to be useful, see its documentation for details. #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet { HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) } @@ -301,6 +304,7 @@ impl HashSet { /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the `HashSet` to be useful, see its documentation for details. #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet { HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) } diff --git a/crates/std/src/env.rs b/crates/std/src/env.rs index 98b2178..edf0127 100644 --- a/crates/std/src/env.rs +++ b/crates/std/src/env.rs @@ -670,6 +670,17 @@ pub fn home_dir() -> Option { /// /// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] / /// [`GetTempPath`][GetTempPath], which this function uses internally. +/// Specifically, for non-SYSTEM processes, the function checks for the +/// following environment variables in order and returns the first path found: +/// +/// 1. The path specified by the `TMP` environment variable. +/// 2. The path specified by the `TEMP` environment variable. +/// 3. The path specified by the `USERPROFILE` environment variable. +/// 4. The Windows directory. +/// +/// When called from a process running as SYSTEM, +/// [`GetTempPath2`][GetTempPath2] returns `C:\Windows\SystemTemp` +/// regardless of environment variables. /// /// Note that, this [may change in the future][changes]. /// diff --git a/crates/std/src/error.rs b/crates/std/src/error.rs index d3e0090..895d43f 100644 --- a/crates/std/src/error.rs +++ b/crates/std/src/error.rs @@ -1,4 +1,562 @@ + // todo retreive docs +#![stable(feature = "rust1", since = "1.0.0")] + #[stable(feature = "rust1", since = "1.0.0")] pub use core::error::Error; #[unstable(feature = "error_generic_member_access", issue = "99301")] pub use core::error::{Request, request_ref, request_value}; + +use crate::backtrace::Backtrace; +use crate::fmt::{self, Write}; + +/// An error reporter that prints an error and its sources. +/// +/// Report also exposes configuration options for formatting the error sources, either entirely on a +/// single line, or in multi-line format with each source on a new line. +/// +/// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the +/// wrapped error be `Send`, `Sync`, or `'static`. +/// +/// # Examples +/// +/// ```rust +/// #![feature(error_reporter)] +/// use std::error::{Error, Report}; +/// use std::fmt; +/// +/// #[derive(Debug)] +/// struct SuperError { +/// source: SuperErrorSideKick, +/// } +/// +/// impl fmt::Display for SuperError { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "SuperError is here!") +/// } +/// } +/// +/// impl Error for SuperError { +/// fn source(&self) -> Option<&(dyn Error + 'static)> { +/// Some(&self.source) +/// } +/// } +/// +/// #[derive(Debug)] +/// struct SuperErrorSideKick; +/// +/// impl fmt::Display for SuperErrorSideKick { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "SuperErrorSideKick is here!") +/// } +/// } +/// +/// impl Error for SuperErrorSideKick {} +/// +/// fn get_super_error() -> Result<(), SuperError> { +/// Err(SuperError { source: SuperErrorSideKick }) +/// } +/// +/// fn main() { +/// match get_super_error() { +/// Err(e) => println!("Error: {}", Report::new(e)), +/// _ => println!("No error"), +/// } +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// ## Output consistency +/// +/// Report prints the same output via `Display` and `Debug`, so it works well with +/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: SuperErrorSideKick, +/// # } +/// # impl fmt::Display for SuperError { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperError is here!") +/// # } +/// # } +/// # impl Error for SuperError { +/// # fn source(&self) -> Option<&(dyn Error + 'static)> { +/// # Some(&self.source) +/// # } +/// # } +/// # #[derive(Debug)] +/// # struct SuperErrorSideKick; +/// # impl fmt::Display for SuperErrorSideKick { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperErrorSideKick is here!") +/// # } +/// # } +/// # impl Error for SuperErrorSideKick {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// get_super_error().map_err(Report::new).unwrap(); +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// thread 'main' panicked at src/error.rs:34:40: +/// called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here! +/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +/// ``` +/// +/// ## Return from `main` +/// +/// `Report` also implements `From` for all types that implement [`Error`]; this when combined with +/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned +/// from `main`. +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: SuperErrorSideKick, +/// # } +/// # impl fmt::Display for SuperError { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperError is here!") +/// # } +/// # } +/// # impl Error for SuperError { +/// # fn source(&self) -> Option<&(dyn Error + 'static)> { +/// # Some(&self.source) +/// # } +/// # } +/// # #[derive(Debug)] +/// # struct SuperErrorSideKick; +/// # impl fmt::Display for SuperErrorSideKick { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperErrorSideKick is here!") +/// # } +/// # } +/// # impl Error for SuperErrorSideKick {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// fn main() -> Result<(), Report> { +/// get_super_error()?; +/// Ok(()) +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line +/// output format. If you want to make sure your `Report`s are pretty printed and include backtrace +/// you will need to manually convert and enable those flags. +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: SuperErrorSideKick, +/// # } +/// # impl fmt::Display for SuperError { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperError is here!") +/// # } +/// # } +/// # impl Error for SuperError { +/// # fn source(&self) -> Option<&(dyn Error + 'static)> { +/// # Some(&self.source) +/// # } +/// # } +/// # #[derive(Debug)] +/// # struct SuperErrorSideKick; +/// # impl fmt::Display for SuperErrorSideKick { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperErrorSideKick is here!") +/// # } +/// # } +/// # impl Error for SuperErrorSideKick {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// fn main() -> Result<(), Report> { +/// get_super_error() +/// .map_err(Report::from) +/// .map_err(|r| r.pretty(true).show_backtrace(true))?; +/// Ok(()) +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here! +/// +/// Caused by: +/// SuperErrorSideKick is here! +/// ``` +#[unstable(feature = "error_reporter", issue = "90172")] +pub struct Report> { + /// The error being reported. + error: E, + /// Whether a backtrace should be included as part of the report. + show_backtrace: bool, + /// Whether the report should be pretty-printed. + pretty: bool, +} + +impl Report +where + Report: From, +{ + /// Creates a new `Report` from an input error. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn new(error: E) -> Report { + Self::from(error) + } +} + +impl Report { + /// Enable pretty-printing the report across multiple lines. + /// + /// # Examples + /// + /// ```rust + /// #![feature(error_reporter)] + /// use std::error::Report; + /// # use std::error::Error; + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: SuperErrorSideKick, + /// # } + /// # impl fmt::Display for SuperError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperError is here!") + /// # } + /// # } + /// # impl Error for SuperError { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKick; + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKick {} + /// + /// let error = SuperError { source: SuperErrorSideKick }; + /// let report = Report::new(error).pretty(true); + /// eprintln!("Error: {report:?}"); + /// ``` + /// + /// This example produces the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// SuperErrorSideKick is here! + /// ``` + /// + /// When there are multiple source errors the causes will be numbered in order of iteration + /// starting from the outermost error. + /// + /// ```rust + /// #![feature(error_reporter)] + /// use std::error::Report; + /// # use std::error::Error; + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: SuperErrorSideKick, + /// # } + /// # impl fmt::Display for SuperError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperError is here!") + /// # } + /// # } + /// # impl Error for SuperError { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKick { + /// # source: SuperErrorSideKickSideKick, + /// # } + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKick { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKickSideKick; + /// # impl fmt::Display for SuperErrorSideKickSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKickSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKickSideKick { } + /// + /// let source = SuperErrorSideKickSideKick; + /// let source = SuperErrorSideKick { source }; + /// let error = SuperError { source }; + /// let report = Report::new(error).pretty(true); + /// eprintln!("Error: {report:?}"); + /// ``` + /// + /// This example produces the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// 0: SuperErrorSideKick is here! + /// 1: SuperErrorSideKickSideKick is here! + /// ``` + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn pretty(mut self, pretty: bool) -> Self { + self.pretty = pretty; + self + } + + /// Display backtrace if available when using pretty output format. + /// + /// # Examples + /// + /// **Note**: Report will search for the first `Backtrace` it can find starting from the + /// outermost error. In this example it will display the backtrace from the second error in the + /// sources, `SuperErrorSideKick`. + /// + /// ```rust + /// #![feature(error_reporter)] + /// #![feature(error_generic_member_access)] + /// # use std::error::Error; + /// # use std::fmt; + /// use std::error::Request; + /// use std::error::Report; + /// use std::backtrace::Backtrace; + /// + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: SuperErrorSideKick, + /// # } + /// # impl fmt::Display for SuperError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperError is here!") + /// # } + /// # } + /// # impl Error for SuperError { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// #[derive(Debug)] + /// struct SuperErrorSideKick { + /// backtrace: Backtrace, + /// } + /// + /// impl SuperErrorSideKick { + /// fn new() -> SuperErrorSideKick { + /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } + /// } + /// } + /// + /// impl Error for SuperErrorSideKick { + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// request.provide_ref::(&self.backtrace); + /// } + /// } + /// + /// // The rest of the example is unchanged ... + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// + /// let source = SuperErrorSideKick::new(); + /// let error = SuperError { source }; + /// let report = Report::new(error).pretty(true).show_backtrace(true); + /// eprintln!("Error: {report:?}"); + /// ``` + /// + /// This example produces something similar to the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// SuperErrorSideKick is here! + /// + /// Stack backtrace: + /// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new + /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 + /// 2: rust_out::main + /// 3: core::ops::function::FnOnce::call_once + /// 4: std::sys::backtrace::__rust_begin_short_backtrace + /// 5: std::rt::lang_start::{{closure}} + /// 6: std::panicking::try + /// 7: std::rt::lang_start_internal + /// 8: std::rt::lang_start + /// 9: main + /// 10: __libc_start_main + /// 11: _start + /// ``` + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { + self.show_backtrace = show_backtrace; + self + } +} + +impl Report +where + E: Error, +{ + fn backtrace(&self) -> Option<&Backtrace> { + // have to grab the backtrace on the first error directly since that error may not be + // 'static + let backtrace = request_ref(&self.error); + let backtrace = backtrace.or_else(|| { + self.error + .source() + .map(|source| source.sources().find_map(|source| request_ref(source))) + .flatten() + }); + backtrace + } + + /// Format the report as a single line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.error)?; + + let sources = self.error.source().into_iter().flat_map(::sources); + + for cause in sources { + write!(f, ": {cause}")?; + } + + Ok(()) + } + + /// Format the report as multiple lines, with each error cause on its own line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let error = &self.error; + + write!(f, "{error}")?; + + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + + let multiple = cause.source().is_some(); + + for (ind, error) in cause.sources().enumerate() { + writeln!(f)?; + let mut indented = Indented { inner: f }; + if multiple { + write!(indented, "{ind: >4}: {error}")?; + } else { + write!(indented, " {error}")?; + } + } + } + + if self.show_backtrace { + if let Some(backtrace) = self.backtrace() { + write!(f, "\n\nStack backtrace:\n{}", backtrace.to_string().trim_end())?; + } + } + + Ok(()) + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl From for Report +where + E: Error, +{ + fn from(error: E) -> Self { + Report { error, show_backtrace: false, pretty: false } + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Display for Report +where + E: Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } + } +} + +// This type intentionally outputs the same format for `Display` and `Debug`for +// situations where you unwrap a `Report` or return it from main. +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Debug for Report +where + Report: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +/// Wrapper type for indenting the inner source. +struct Indented<'a, D> { + inner: &'a mut D, +} + +impl Write for Indented<'_, T> +where + T: Write, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + for (i, line) in s.split('\n').enumerate() { + if i > 0 { + self.inner.write_char('\n')?; + self.inner.write_str(" ")?; + } + + self.inner.write_str(line)?; + } + + Ok(()) + } +} diff --git a/crates/std/src/ffi/os_str.rs b/crates/std/src/ffi/os_str.rs index bd6d62c..b07ae69 100644 --- a/crates/std/src/ffi/os_str.rs +++ b/crates/std/src/ffi/os_str.rs @@ -11,7 +11,7 @@ use crate::hash::{Hash, Hasher}; use crate::ops::{self, Range}; use crate::rc::Rc; use crate::str::FromStr; -use alloc_crate::sync::Arc; +use crate::sync::Arc; use crate::sys::os_str::{Buf, Slice}; use crate::sys::{AsInner, FromInner, IntoInner}; use crate::{cmp, fmt, slice}; @@ -576,15 +576,21 @@ impl OsString { /// Truncate the `OsString` to the specified length. /// + /// If `new_len` is greater than the string's current length, this has no + /// effect. + /// /// # Panics + /// /// Panics if `len` does not lie on a valid `OsStr` boundary /// (as described in [`OsStr::slice_encoded_bytes`]). #[inline] #[unstable(feature = "os_string_truncate", issue = "133262")] pub fn truncate(&mut self, len: usize) { - self.as_os_str().inner.check_public_boundary(len); - // SAFETY: The length was just checked to be at a valid boundary. - unsafe { self.inner.truncate_unchecked(len) }; + if len <= self.len() { + self.as_os_str().inner.check_public_boundary(len); + // SAFETY: The length was just checked to be at a valid boundary. + unsafe { self.inner.truncate_unchecked(len) }; + } } /// Provides plumbing to `Vec::extend_from_slice` without giving full diff --git a/crates/std/src/fs.rs b/crates/std/src/fs.rs index b9e3361..885bf37 100644 --- a/crates/std/src/fs.rs +++ b/crates/std/src/fs.rs @@ -36,7 +36,6 @@ target_os = "wasi", target_env = "sgx", target_os = "xous", - target_os = "survos", target_os = "trusty", )) ))] @@ -46,7 +45,7 @@ use crate::ffi::OsString; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sealed::Sealed; -use alloc::sync::Arc; +use crate::sync::Arc; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp}; use crate::time::SystemTime; use crate::{error, fmt}; @@ -2681,7 +2680,7 @@ impl AsInner for DirEntry { /// /// This function will only ever return an error of kind `NotFound` if the given /// path does not exist. Note that the inverse is not true, -/// ie. if a path does not exist, its removal may fail for a number of reasons, +/// i.e. if a path does not exist, its removal may fail for a number of reasons, /// such as insufficient permissions. /// /// # Examples @@ -3151,7 +3150,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// /// This function will only ever return an error of kind `NotFound` if the given /// path does not exist. Note that the inverse is not true, -/// ie. if a path does not exist, its removal may fail for a number of reasons, +/// i.e. if a path does not exist, its removal may fail for a number of reasons, /// such as insufficient permissions. /// /// # Examples diff --git a/crates/std/src/io.rs b/crates/std/src/io.rs index 70095b3..679fa0b 100644 --- a/crates/std/src/io.rs +++ b/crates/std/src/io.rs @@ -21,12 +21,14 @@ pub use core::io::{BorrowedBuf, BorrowedCursor}; use core::slice::memchr; pub use cursor::Cursor; -pub use self::stdio::{ - Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout, -}; +pub use self::copy::copy; pub use self::pipe::{PipeReader, PipeWriter}; -pub use stdio::try_set_output_capture; +pub use self::stdio::cleanup; +pub use self::stdio::{ + _print, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout, +}; pub(crate) use stdio::attempt_print_to_stderr; +pub use stdio::try_set_output_capture; use crate::fs::File; use io::IoBase; @@ -43,7 +45,7 @@ impl IoBase for Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> core::result::Result { - unsafe { File::from_raw_fd(0).read(buf) } + unsafe { crate::other_fs::File::from_raw_fd(0).read(buf) } } } diff --git a/crates/std/src/keyword_docs.rs b/crates/std/src/keyword_docs.rs new file mode 100644 index 0000000..dc0d11b --- /dev/null +++ b/crates/std/src/keyword_docs.rs @@ -0,0 +1,2754 @@ +#[doc(keyword = "as")] +// +/// Cast between types, rename an import, or qualify paths to associated items. +/// +/// # Type casting +/// +/// `as` is most commonly used to turn primitive types into other primitive types, but it has other +/// uses that include turning pointers into addresses, addresses into pointers, and pointers into +/// other pointers. +/// +/// ```rust +/// let thing1: u8 = 89.0 as u8; +/// assert_eq!('B' as u32, 66); +/// assert_eq!(thing1 as char, 'Y'); +/// let thing2: f32 = thing1 as f32 + 10.5; +/// assert_eq!(true as u8 + thing2 as u8, 100); +/// ``` +/// +/// In general, any cast that can be performed via ascribing the type can also be done using `as`, +/// so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (note: `let x: u32 +/// = 123` would be best in that situation). The same is not true in the other direction, however; +/// explicitly using `as` allows a few more coercions that aren't allowed implicitly, such as +/// changing the type of a raw pointer or turning closures into raw pointers. +/// +/// `as` can be seen as the primitive for `From` and `Into`: `as` only works with primitives +/// (`u8`, `bool`, `str`, pointers, ...) whereas `From` and `Into` also works with types like +/// `String` or `Vec`. +/// +/// `as` can also be used with the `_` placeholder when the destination type can be inferred. Note +/// that this can cause inference breakage and usually such code should use an explicit type for +/// both clarity and stability. This is most useful when converting pointers using `as *const _` or +/// `as *mut _` though the [`cast`][const-cast] method is recommended over `as *const _` and it is +/// [the same][mut-cast] for `as *mut _`: those methods make the intent clearer. +/// +/// # Renaming imports +/// +/// `as` is also used to rename imports in [`use`] and [`extern crate`][`crate`] statements: +/// +/// ``` +/// # #[allow(unused_imports)] +/// use std::{mem as memory, net as network}; +/// // Now you can use the names `memory` and `network` to refer to `std::mem` and `std::net`. +/// ``` +/// +/// # Qualifying paths +/// +/// You'll also find with `From` and `Into`, and indeed all traits, that `as` is used for the +/// _fully qualified path_, a means of disambiguating associated items, i.e. functions, +/// constants, and types. For example, if you have a type which implements two traits with identical +/// method names (e.g. `Into::::into` and `Into::::into`), you can clarify which method +/// you'll use with `>::into(my_thing)`[^as-use-from]. This is quite verbose, +/// but fortunately, Rust's type inference usually saves you from needing this, although it is +/// occasionally necessary, especially with methods that return a generic type like `Into::into` or +/// methods that don't take `self`. It's more common to use in macros where it can provide necessary +/// hygiene. +/// +/// [^as-use-from]: You should probably never use this syntax with `Into` and instead write +/// `T::from(my_thing)`. It just happens that there aren't any great examples for this syntax in +/// the standard library. Also, at time of writing, the compiler tends to suggest fully-qualified +/// paths to fix ambiguous `Into::into` calls, so the example should hopefully be familiar. +/// +/// # Further reading +/// +/// For more information on what `as` is capable of, see the Reference on [type cast expressions], +/// [renaming imported entities], [renaming `extern` crates] +/// and [qualified paths]. +/// +/// [type cast expressions]: ../reference/expressions/operator-expr.html#type-cast-expressions +/// [renaming imported entities]: https://doc.rust-lang.org/reference/items/use-declarations.html#as-renames +/// [renaming `extern` crates]: https://doc.rust-lang.org/reference/items/extern-crates.html#r-items.extern-crate.as +/// [qualified paths]: ../reference/paths.html#qualified-paths +/// [`crate`]: keyword.crate.html +/// [`use`]: keyword.use.html +/// [const-cast]: pointer::cast +/// [mut-cast]: primitive.pointer.html#method.cast-1 +mod as_keyword {} + +#[doc(keyword = "break")] +// +/// Exit early from a loop or labelled block. +/// +/// When `break` is encountered, execution of the associated loop body is +/// immediately terminated. +/// +/// ```rust +/// let mut last = 0; +/// +/// for x in 1..100 { +/// if x > 12 { +/// break; +/// } +/// last = x; +/// } +/// +/// assert_eq!(last, 12); +/// println!("{last}"); +/// ``` +/// +/// A break expression is normally associated with the innermost loop enclosing the +/// `break` but a label can be used to specify which enclosing loop is affected. +/// +/// ```rust +/// 'outer: for i in 1..=5 { +/// println!("outer iteration (i): {i}"); +/// +/// '_inner: for j in 1..=200 { +/// println!(" inner iteration (j): {j}"); +/// if j >= 3 { +/// // breaks from inner loop, lets outer loop continue. +/// break; +/// } +/// if i >= 2 { +/// // breaks from outer loop, and directly to "Bye". +/// break 'outer; +/// } +/// } +/// } +/// println!("Bye."); +/// ``` +/// +/// When associated with `loop`, a break expression may be used to return a value from that loop. +/// This is only valid with `loop` and not with any other type of loop. +/// If no value is specified for `break;` it returns `()`. +/// Every `break` within a loop must return the same type. +/// +/// ```rust +/// let (mut a, mut b) = (1, 1); +/// let result = loop { +/// if b > 10 { +/// break b; +/// } +/// let c = a + b; +/// a = b; +/// b = c; +/// }; +/// // first number in Fibonacci sequence over 10: +/// assert_eq!(result, 13); +/// println!("{result}"); +/// ``` +/// +/// It is also possible to exit from any *labelled* block returning the value early. +/// If no value is specified for `break;` it returns `()`. +/// +/// ```rust +/// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; +/// +/// let mut results = vec![]; +/// for input in inputs { +/// let result = 'filter: { +/// if input.len() > 3 { +/// break 'filter Err("Too long"); +/// }; +/// +/// if !input.contains("C") { +/// break 'filter Err("No Cs"); +/// }; +/// +/// Ok(input.to_uppercase()) +/// }; +/// +/// results.push(result); +/// } +/// +/// // [Ok("COW"), Ok("CAT"), Err("No Cs"), Err("Too long"), Ok("COD")] +/// println!("{:?}", results) +/// ``` +/// +/// For more details consult the [Reference on "break expression"] and the [Reference on "break and +/// loop values"]. +/// +/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions +/// [Reference on "break and loop values"]: +/// ../reference/expressions/loop-expr.html#break-and-loop-values +mod break_keyword {} + +#[doc(keyword = "const")] +// +/// Compile-time constants, compile-time blocks, compile-time evaluable functions, and raw pointers. +/// +/// ## Compile-time constants +/// +/// Sometimes a certain value is used many times throughout a program, and it can become +/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to +/// make it a variable that gets carried around to each function that needs it. In these cases, the +/// `const` keyword provides a convenient alternative to code duplication: +/// +/// ```rust +/// const THING: u32 = 0xABAD1DEA; +/// +/// let foo = 123 + THING; +/// ``` +/// +/// Constants must be explicitly typed; unlike with `let`, you can't ignore their type and let the +/// compiler figure it out. Any constant value can be defined in a `const`, which in practice happens +/// to be most things that would be reasonable to have in a constant (barring `const fn`s). For +/// example, you can't have a [`File`] as a `const`. +/// +/// [`File`]: crate::fs::File +/// +/// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses +/// all others in a Rust program. For example, if you wanted to define a constant string, it would +/// look like this: +/// +/// ```rust +/// const WORDS: &'static str = "hello rust!"; +/// ``` +/// +/// Thanks to static lifetime elision, you usually don't have to explicitly use `'static`: +/// +/// ```rust +/// const WORDS: &str = "hello convenience!"; +/// ``` +/// +/// `const` items look remarkably similar to `static` items, which introduces some confusion as +/// to which one should be used at which times. To put it simply, constants are inlined wherever +/// they're used, making using them identical to simply replacing the name of the `const` with its +/// value. Static variables, on the other hand, point to a single location in memory, which all +/// accesses share. This means that, unlike with constants, they can't have destructors, and act as +/// a single value across the entire codebase. +/// +/// Constants, like statics, should always be in `SCREAMING_SNAKE_CASE`. +/// +/// For more detail on `const`, see the [Rust Book] or the [Reference]. +/// +/// ## Compile-time blocks +/// +/// The `const` keyword can also be used to define a block of code that is evaluated at compile time. +/// This is useful for ensuring certain computations are completed before optimizations happen, as well as +/// before runtime. For more details, see the [Reference][const-blocks]. +/// +/// ## Compile-time evaluable functions +/// +/// The other main use of the `const` keyword is in `const fn`. This marks a function as being +/// callable in the body of a `const` or `static` item and in array initializers (commonly called +/// "const contexts"). `const fn` are restricted in the set of operations they can perform, to +/// ensure that they can be evaluated at compile-time. See the [Reference][const-eval] for more +/// detail. +/// +/// Turning a `fn` into a `const fn` has no effect on run-time uses of that function. +/// +/// ## Other uses of `const` +/// +/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const +/// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive]. +/// +/// [pointer primitive]: pointer +/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#constants +/// [Reference]: ../reference/items/constant-items.html +/// [const-blocks]: ../reference/expressions/block-expr.html#const-blocks +/// [const-eval]: ../reference/const_eval.html +mod const_keyword {} + +#[doc(keyword = "continue")] +// +/// Skip to the next iteration of a loop. +/// +/// When `continue` is encountered, the current iteration is terminated, returning control to the +/// loop head, typically continuing with the next iteration. +/// +/// ```rust +/// // Printing odd numbers by skipping even ones +/// for number in 1..=10 { +/// if number % 2 == 0 { +/// continue; +/// } +/// println!("{number}"); +/// } +/// ``` +/// +/// Like `break`, `continue` is normally associated with the innermost enclosing loop, but labels +/// may be used to specify the affected loop. +/// +/// ```rust +/// // Print Odd numbers under 30 with unit <= 5 +/// 'tens: for ten in 0..3 { +/// '_units: for unit in 0..=9 { +/// if unit % 2 == 0 { +/// continue; +/// } +/// if unit > 5 { +/// continue 'tens; +/// } +/// println!("{}", ten * 10 + unit); +/// } +/// } +/// ``` +/// +/// See [continue expressions] from the reference for more details. +/// +/// [continue expressions]: ../reference/expressions/loop-expr.html#continue-expressions +mod continue_keyword {} + +#[doc(keyword = "crate")] +// +/// A Rust binary or library. +/// +/// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are +/// used to specify a dependency on a crate external to the one it's declared in. Crates are the +/// fundamental compilation unit of Rust code, and can be seen as libraries or projects. More can +/// be read about crates in the [Reference]. +/// +/// ```rust ignore +/// extern crate rand; +/// extern crate my_crate as thing; +/// extern crate std; // implicitly added to the root of every Rust project +/// ``` +/// +/// The `as` keyword can be used to change what the crate is referred to as in your project. If a +/// crate name includes a dash, it is implicitly imported with the dashes replaced by underscores. +/// +/// `crate` can also be used as in conjunction with `pub` to signify that the item it's attached to +/// is public only to other members of the same crate it's in. +/// +/// ```rust +/// # #[allow(unused_imports)] +/// pub(crate) use std::io::Error as IoError; +/// pub(crate) enum CoolMarkerType { } +/// pub struct PublicThing { +/// pub(crate) semi_secret_thing: bool, +/// } +/// ``` +/// +/// `crate` is also used to represent the absolute path of a module, where `crate` refers to the +/// root of the current crate. For instance, `crate::foo::bar` refers to the name `bar` inside the +/// module `foo`, from anywhere else in the same crate. +/// +/// [Reference]: ../reference/items/extern-crates.html +mod crate_keyword {} + +#[doc(keyword = "else")] +// +/// What expression to evaluate when an [`if`] condition evaluates to [`false`]. +/// +/// `else` expressions are optional. When no else expressions are supplied it is assumed to evaluate +/// to the unit type `()`. +/// +/// The type that the `else` blocks evaluate to must be compatible with the type that the `if` block +/// evaluates to. +/// +/// As can be seen below, `else` must be followed by either: `if`, `if let`, or a block `{}` and it +/// will return the value of that expression. +/// +/// ```rust +/// let result = if true == false { +/// "oh no" +/// } else if "something" == "other thing" { +/// "oh dear" +/// } else if let Some(200) = "blarg".parse::().ok() { +/// "uh oh" +/// } else { +/// println!("Sneaky side effect."); +/// "phew, nothing's broken" +/// }; +/// ``` +/// +/// Here's another example but here we do not try and return an expression: +/// +/// ```rust +/// if true == false { +/// println!("oh no"); +/// } else if "something" == "other thing" { +/// println!("oh dear"); +/// } else if let Some(200) = "blarg".parse::().ok() { +/// println!("uh oh"); +/// } else { +/// println!("phew, nothing's broken"); +/// } +/// ``` +/// +/// The above is _still_ an expression but it will always evaluate to `()`. +/// +/// There is possibly no limit to the number of `else` blocks that could follow an `if` expression +/// however if you have several then a [`match`] expression might be preferable. +/// +/// Read more about control flow in the [Rust Book]. +/// +/// [Rust Book]: ../book/ch03-05-control-flow.html#handling-multiple-conditions-with-else-if +/// [`match`]: keyword.match.html +/// [`false`]: keyword.false.html +/// [`if`]: keyword.if.html +mod else_keyword {} + +#[doc(keyword = "enum")] +// +/// A type that can be any one of several variants. +/// +/// Enums in Rust are similar to those of other compiled languages like C, but have important +/// differences that make them considerably more powerful. What Rust calls enums are more commonly +/// known as [Algebraic Data Types][ADT] if you're coming from a functional programming background. +/// The important detail is that each enum variant can have data to go along with it. +/// +/// ```rust +/// # struct Coord; +/// enum SimpleEnum { +/// FirstVariant, +/// SecondVariant, +/// ThirdVariant, +/// } +/// +/// enum Location { +/// Unknown, +/// Anonymous, +/// Known(Coord), +/// } +/// +/// enum ComplexEnum { +/// Nothing, +/// Something(u32), +/// LotsOfThings { +/// usual_struct_stuff: bool, +/// blah: String, +/// } +/// } +/// +/// enum EmptyEnum { } +/// ``` +/// +/// The first enum shown is the usual kind of enum you'd find in a C-style language. The second +/// shows off a hypothetical example of something storing location data, with `Coord` being any +/// other type that's needed, for example a struct. The third example demonstrates the kind of +/// data a variant can store, ranging from nothing, to a tuple, to an anonymous struct. +/// +/// Instantiating enum variants involves explicitly using the enum's name as its namespace, +/// followed by one of its variants. `SimpleEnum::SecondVariant` would be an example from above. +/// When data follows along with a variant, such as with rust's built-in [`Option`] type, the data +/// is added as the type describes, for example `Option::Some(123)`. The same follows with +/// struct-like variants, with things looking like `ComplexEnum::LotsOfThings { usual_struct_stuff: +/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to [`!`] in that they cannot be +/// instantiated at all, and are used mainly to mess with the type system in interesting ways. +/// +/// For more information, take a look at the [Rust Book] or the [Reference] +/// +/// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type +/// [Rust Book]: ../book/ch06-01-defining-an-enum.html +/// [Reference]: ../reference/items/enumerations.html +mod enum_keyword {} + +#[doc(keyword = "extern")] +// +/// Link to or import external code. +/// +/// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`] +/// keyword to make your Rust code aware of other Rust crates in your project, i.e., `extern crate +/// lazy_static;`. The other use is in foreign function interfaces (FFI). +/// +/// `extern` is used in two different contexts within FFI. The first is in the form of external +/// blocks, for declaring function interfaces that Rust code can call foreign code by. This use +/// of `extern` is unsafe, since we are asserting to the compiler that all function declarations +/// are correct. If they are not, using these items may lead to undefined behavior. +/// +/// ```rust ignore +/// // SAFETY: The function declarations given below are in +/// // line with the header files of `my_c_library`. +/// #[link(name = "my_c_library")] +/// unsafe extern "C" { +/// fn my_c_function(x: i32) -> bool; +/// } +/// ``` +/// +/// This code would attempt to link with `libmy_c_library.so` on unix-like systems and +/// `my_c_library.dll` on Windows at runtime, and panic if it can't find something to link to. Rust +/// code could then use `my_c_function` as if it were any other unsafe Rust function. Working with +/// non-Rust languages and FFI is inherently unsafe, so wrappers are usually built around C APIs. +/// +/// The mirror use case of FFI is also done via the `extern` keyword: +/// +/// ```rust +/// #[unsafe(no_mangle)] +/// pub extern "C" fn callable_from_c(x: i32) -> bool { +/// x % 3 == 0 +/// } +/// ``` +/// +/// If compiled as a dylib, the resulting .so could then be linked to from a C library, and the +/// function could be used as if it was from any other library. +/// +/// For more information on FFI, check the [Rust book] or the [Reference]. +/// +/// [Rust book]: +/// ../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code +/// [Reference]: ../reference/items/external-blocks.html +/// [`crate`]: keyword.crate.html +mod extern_keyword {} + +#[doc(keyword = "false")] +// +/// A value of type [`bool`] representing logical **false**. +/// +/// `false` is the logical opposite of [`true`]. +/// +/// See the documentation for [`true`] for more information. +/// +/// [`true`]: keyword.true.html +mod false_keyword {} + +#[doc(keyword = "fn")] +// +/// A function or function pointer. +/// +/// Functions are the primary way code is executed within Rust. Function blocks, usually just +/// called functions, can be defined in a variety of different places and be assigned many +/// different attributes and modifiers. +/// +/// Standalone functions that just sit within a module not attached to anything else are common, +/// but most functions will end up being inside [`impl`] blocks, either on another type itself, or +/// as a trait impl for that type. +/// +/// ```rust +/// fn standalone_function() { +/// // code +/// } +/// +/// pub fn public_thing(argument: bool) -> String { +/// // code +/// # "".to_string() +/// } +/// +/// struct Thing { +/// foo: i32, +/// } +/// +/// impl Thing { +/// pub fn new() -> Self { +/// Self { +/// foo: 42, +/// } +/// } +/// } +/// ``` +/// +/// In addition to presenting fixed types in the form of `fn name(arg: type, ..) -> return_type`, +/// functions can also declare a list of type parameters along with trait bounds that they fall +/// into. +/// +/// ```rust +/// fn generic_function(x: T) -> (T, T, T) { +/// (x.clone(), x.clone(), x.clone()) +/// } +/// +/// fn generic_where(x: T) -> T +/// where T: std::ops::Add + Copy +/// { +/// x + x + x +/// } +/// ``` +/// +/// Declaring trait bounds in the angle brackets is functionally identical to using a `where` +/// clause. It's up to the programmer to decide which works better in each situation, but `where` +/// tends to be better when things get longer than one line. +/// +/// Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in +/// FFI. +/// +/// For more information on the various types of functions and how they're used, consult the [Rust +/// book] or the [Reference]. +/// +/// [`impl`]: keyword.impl.html +/// [`extern`]: keyword.extern.html +/// [Rust book]: ../book/ch03-03-how-functions-work.html +/// [Reference]: ../reference/items/functions.html +mod fn_keyword {} + +#[doc(keyword = "for")] +// +/// Iteration with [`in`], trait implementation with [`impl`], or [higher-ranked trait bounds] +/// (`for<'a>`). +/// +/// The `for` keyword is used in many syntactic locations: +/// +/// * `for` is used in for-in-loops (see below). +/// * `for` is used when implementing traits as in `impl Trait for Type` (see [`impl`] for more info +/// on that). +/// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq`. +/// +/// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common +/// practice within Rust, which is to loop over anything that implements [`IntoIterator`] until the +/// iterator returned by `.into_iter()` returns `None` (or the loop body uses `break`). +/// +/// ```rust +/// for i in 0..5 { +/// println!("{}", i * 2); +/// } +/// +/// for i in std::iter::repeat(5) { +/// println!("turns out {i} never stops being 5"); +/// break; // would loop forever otherwise +/// } +/// +/// 'outer: for x in 5..50 { +/// for y in 0..10 { +/// if x == y { +/// break 'outer; +/// } +/// } +/// } +/// ``` +/// +/// As shown in the example above, `for` loops (along with all other loops) can be tagged, using +/// similar syntax to lifetimes (only visually similar, entirely distinct in practice). Giving the +/// same tag to `break` breaks the tagged loop, which is useful for inner loops. It is definitely +/// not a goto. +/// +/// A `for` loop expands as shown: +/// +/// ```rust +/// # fn code() { } +/// # let iterator = 0..2; +/// for loop_variable in iterator { +/// code() +/// } +/// ``` +/// +/// ```rust +/// # fn code() { } +/// # let iterator = 0..2; +/// { +/// let result = match IntoIterator::into_iter(iterator) { +/// mut iter => loop { +/// match iter.next() { +/// None => break, +/// Some(loop_variable) => { code(); }, +/// }; +/// }, +/// }; +/// result +/// } +/// ``` +/// +/// More details on the functionality shown can be seen at the [`IntoIterator`] docs. +/// +/// For more information on for-loops, see the [Rust book] or the [Reference]. +/// +/// See also, [`loop`], [`while`]. +/// +/// [`in`]: keyword.in.html +/// [`impl`]: keyword.impl.html +/// [`loop`]: keyword.loop.html +/// [`while`]: keyword.while.html +/// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds +/// [Rust book]: +/// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for +/// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops +mod for_keyword {} + +#[doc(keyword = "if")] +// +/// Evaluate a block if a condition holds. +/// +/// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in +/// your code. However, unlike in most languages, `if` blocks can also act as expressions. +/// +/// ```rust +/// # let rude = true; +/// if 1 == 2 { +/// println!("whoops, mathematics broke"); +/// } else { +/// println!("everything's fine!"); +/// } +/// +/// let greeting = if rude { +/// "sup nerd." +/// } else { +/// "hello, friend!" +/// }; +/// +/// if let Ok(x) = "123".parse::() { +/// println!("{} double that and you get {}!", greeting, x * 2); +/// } +/// ``` +/// +/// Shown above are the three typical forms an `if` block comes in. First is the usual kind of +/// thing you'd see in many languages, with an optional `else` block. Second uses `if` as an +/// expression, which is only possible if all branches return the same type. An `if` expression can +/// be used everywhere you'd expect. The third kind of `if` block is an `if let` block, which +/// behaves similarly to using a `match` expression: +/// +/// ```rust +/// if let Some(x) = Some(123) { +/// // code +/// # let _ = x; +/// } else { +/// // something else +/// } +/// +/// match Some(123) { +/// Some(x) => { +/// // code +/// # let _ = x; +/// }, +/// _ => { +/// // something else +/// }, +/// } +/// ``` +/// +/// Each kind of `if` expression can be mixed and matched as needed. +/// +/// ```rust +/// if true == false { +/// println!("oh no"); +/// } else if "something" == "other thing" { +/// println!("oh dear"); +/// } else if let Some(200) = "blarg".parse::().ok() { +/// println!("uh oh"); +/// } else { +/// println!("phew, nothing's broken"); +/// } +/// ``` +/// +/// The `if` keyword is used in one other place in Rust, namely as a part of pattern matching +/// itself, allowing patterns such as `Some(x) if x > 200` to be used. +/// +/// For more information on `if` expressions, see the [Rust book] or the [Reference]. +/// +/// [Rust book]: ../book/ch03-05-control-flow.html#if-expressions +/// [Reference]: ../reference/expressions/if-expr.html +mod if_keyword {} + +#[doc(keyword = "impl")] +// +/// Implementations of functionality for a type, or a type implementing some functionality. +/// +/// There are two uses of the keyword `impl`: +/// * An `impl` block is an item that is used to implement some functionality for a type. +/// * An `impl Trait` in a type-position can be used to designate a type that implements a trait called `Trait`. +/// +/// # Implementing Functionality for a Type +/// +/// The `impl` keyword is primarily used to define implementations on types. Inherent +/// implementations are standalone, while trait implementations are used to implement traits for +/// types, or other traits. +/// +/// An implementation consists of definitions of functions and consts. A function defined in an +/// `impl` block can be standalone, meaning it would be called like `Vec::new()`. If the function +/// takes `self`, `&self`, or `&mut self` as its first argument, it can also be called using +/// method-call syntax, a familiar feature to any object-oriented programmer, like `vec.len()`. +/// +/// ## Inherent Implementations +/// +/// ```rust +/// struct Example { +/// number: i32, +/// } +/// +/// impl Example { +/// fn boo() { +/// println!("boo! Example::boo() was called!"); +/// } +/// +/// fn answer(&mut self) { +/// self.number += 42; +/// } +/// +/// fn get_number(&self) -> i32 { +/// self.number +/// } +/// } +/// ``` +/// +/// It matters little where an inherent implementation is defined; +/// its functionality is in scope wherever its implementing type is. +/// +/// ## Trait Implementations +/// +/// ```rust +/// struct Example { +/// number: i32, +/// } +/// +/// trait Thingy { +/// fn do_thingy(&self); +/// } +/// +/// impl Thingy for Example { +/// fn do_thingy(&self) { +/// println!("doing a thing! also, number is {}!", self.number); +/// } +/// } +/// ``` +/// +/// It matters little where a trait implementation is defined; +/// its functionality can be brought into scope by importing the trait it implements. +/// +/// For more information on implementations, see the [Rust book][book1] or the [Reference]. +/// +/// # Designating a Type that Implements Some Functionality +/// +/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be understood to mean +/// "any (or some) concrete type that implements Trait". +/// It can be used as the type of a variable declaration, +/// in [argument position](https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html) +/// or in [return position](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). +/// One pertinent use case is in working with closures, which have unnameable types. +/// +/// ```rust +/// fn thing_returning_closure() -> impl Fn(i32) -> bool { +/// println!("here's a closure for you!"); +/// |x: i32| x % 3 == 0 +/// } +/// ``` +/// +/// For more information on `impl Trait` syntax, see the [Rust book][book2]. +/// +/// [book1]: ../book/ch05-03-method-syntax.html +/// [Reference]: ../reference/items/implementations.html +/// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits +mod impl_keyword {} + +#[doc(keyword = "in")] +// +/// Iterate over a series of values with [`for`]. +/// +/// The expression immediately following `in` must implement the [`IntoIterator`] trait. +/// +/// ## Literal Examples: +/// +/// * `for _ in 1..3 {}` - Iterate over an exclusive range up to but excluding 3. +/// * `for _ in 1..=3 {}` - Iterate over an inclusive range up to and including 3. +/// +/// (Read more about [range patterns]) +/// +/// [`IntoIterator`]: ../book/ch13-04-performance.html +/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns +/// [`for`]: keyword.for.html +/// +/// The other use of `in` is with the keyword `pub`. It allows users to declare an item as visible +/// only within a given scope. +/// +/// ## Literal Example: +/// +/// * `pub(in crate::outer_mod) fn outer_mod_visible_fn() {}` - fn is visible in `outer_mod` +/// +/// Starting with the 2018 edition, paths for `pub(in path)` must start with `crate`, `self` or +/// `super`. The 2015 edition may also use paths starting with `::` or modules from the crate root. +/// +/// For more information, see the [Reference]. +/// +/// [Reference]: ../reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself +mod in_keyword {} + +#[doc(keyword = "let")] +// +/// Bind a value to a variable. +/// +/// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new +/// set of variables into the current scope, as given by a pattern. +/// +/// ```rust +/// # #![allow(unused_assignments)] +/// let thing1: i32 = 100; +/// let thing2 = 200 + thing1; +/// +/// let mut changing_thing = true; +/// changing_thing = false; +/// +/// let (part1, part2) = ("first", "second"); +/// +/// struct Example { +/// a: bool, +/// b: u64, +/// } +/// +/// let Example { a, b: _ } = Example { +/// a: true, +/// b: 10004, +/// }; +/// assert!(a); +/// ``` +/// +/// The pattern is most commonly a single variable, which means no pattern matching is done and +/// the expression given is bound to the variable. Apart from that, patterns used in `let` bindings +/// can be as complicated as needed, given that the pattern is exhaustive. See the [Rust +/// book][book1] for more information on pattern matching. The type of the pattern is optionally +/// given afterwards, but if left blank is automatically inferred by the compiler if possible. +/// +/// Variables in Rust are immutable by default, and require the `mut` keyword to be made mutable. +/// +/// Multiple variables can be defined with the same name, known as shadowing. This doesn't affect +/// the original variable in any way beyond being unable to directly access it beyond the point of +/// shadowing. It continues to remain in scope, getting dropped only when it falls out of scope. +/// Shadowed variables don't need to have the same type as the variables shadowing them. +/// +/// ```rust +/// let shadowing_example = true; +/// let shadowing_example = 123.4; +/// let shadowing_example = shadowing_example as u32; +/// let mut shadowing_example = format!("cool! {shadowing_example}"); +/// shadowing_example += " something else!"; // not shadowing +/// ``` +/// +/// Other places the `let` keyword is used include along with [`if`], in the form of `if let` +/// expressions. They're useful if the pattern being matched isn't exhaustive, such as with +/// enumerations. `while let` also exists, which runs a loop with a pattern matched value until +/// that pattern can't be matched. +/// +/// For more information on the `let` keyword, see the [Rust book][book2] or the [Reference] +/// +/// [book1]: ../book/ch06-02-match.html +/// [`if`]: keyword.if.html +/// [book2]: ../book/ch18-01-all-the-places-for-patterns.html#let-statements +/// [Reference]: ../reference/statements.html#let-statements +mod let_keyword {} + +#[doc(keyword = "loop")] +// +/// Loop indefinitely. +/// +/// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside +/// it until the code uses `break` or the program exits. +/// +/// ```rust +/// loop { +/// println!("hello world forever!"); +/// # break; +/// } +/// +/// let mut i = 1; +/// loop { +/// println!("i is {i}"); +/// if i > 100 { +/// break; +/// } +/// i *= 2; +/// } +/// assert_eq!(i, 128); +/// ``` +/// +/// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as +/// expressions that return values via `break`. +/// +/// ```rust +/// let mut i = 1; +/// let something = loop { +/// i *= 2; +/// if i > 100 { +/// break i; +/// } +/// }; +/// assert_eq!(something, 128); +/// ``` +/// +/// Every `break` in a loop has to have the same type. When it's not explicitly giving something, +/// `break;` returns `()`. +/// +/// For more information on `loop` and loops in general, see the [Reference]. +/// +/// See also, [`for`], [`while`]. +/// +/// [`for`]: keyword.for.html +/// [`while`]: keyword.while.html +/// [Reference]: ../reference/expressions/loop-expr.html +mod loop_keyword {} + +#[doc(keyword = "match")] +// +/// Control flow based on pattern matching. +/// +/// `match` can be used to run code conditionally. Every pattern must +/// be handled exhaustively either explicitly or by using wildcards like +/// `_` in the `match`. Since `match` is an expression, values can also be +/// returned. +/// +/// ```rust +/// let opt = Option::None::; +/// let x = match opt { +/// Some(int) => int, +/// None => 10, +/// }; +/// assert_eq!(x, 10); +/// +/// let a_number = Option::Some(10); +/// match a_number { +/// Some(x) if x <= 5 => println!("0 to 5 num = {x}"), +/// Some(x @ 6..=10) => println!("6 to 10 num = {x}"), +/// None => panic!(), +/// // all other numbers +/// _ => panic!(), +/// } +/// ``` +/// +/// `match` can be used to gain access to the inner members of an enum +/// and use them directly. +/// +/// ```rust +/// enum Outer { +/// Double(Option, Option), +/// Single(Option), +/// Empty +/// } +/// +/// let get_inner = Outer::Double(None, Some(String::new())); +/// match get_inner { +/// Outer::Double(None, Some(st)) => println!("{st}"), +/// Outer::Single(opt) => println!("{opt:?}"), +/// _ => panic!(), +/// } +/// ``` +/// +/// For more information on `match` and matching in general, see the [Reference]. +/// +/// [Reference]: ../reference/expressions/match-expr.html +mod match_keyword {} + +#[doc(keyword = "mod")] +// +/// Organize code into [modules]. +/// +/// Use `mod` to create new [modules] to encapsulate code, including other +/// modules: +/// +/// ``` +/// mod foo { +/// mod bar { +/// type MyType = (u8, u8); +/// fn baz() {} +/// } +/// } +/// ``` +/// +/// Like [`struct`]s and [`enum`]s, a module and its content are private by +/// default, inaccessible to code outside of the module. +/// +/// To learn more about allowing access, see the documentation for the [`pub`] +/// keyword. +/// +/// [`enum`]: keyword.enum.html +/// [`pub`]: keyword.pub.html +/// [`struct`]: keyword.struct.html +/// [modules]: ../reference/items/modules.html +mod mod_keyword {} + +#[doc(keyword = "move")] +// +/// Capture a [closure]'s environment by value. +/// +/// `move` converts any variables captured by reference or mutable reference +/// to variables captured by value. +/// +/// ```rust +/// let data = vec![1, 2, 3]; +/// let closure = move || println!("captured {data:?} by value"); +/// +/// // data is no longer available, it is owned by the closure +/// ``` +/// +/// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though +/// they capture variables by `move`. This is because the traits implemented by +/// a closure type are determined by *what* the closure does with captured +/// values, not *how* it captures them: +/// +/// ```rust +/// fn create_fn() -> impl Fn() { +/// let text = "Fn".to_owned(); +/// move || println!("This is a: {text}") +/// } +/// +/// let fn_plain = create_fn(); +/// fn_plain(); +/// ``` +/// +/// `move` is often used when [threads] are involved. +/// +/// ```rust +/// let data = vec![1, 2, 3]; +/// +/// std::thread::spawn(move || { +/// println!("captured {data:?} by value") +/// }).join().unwrap(); +/// +/// // data was moved to the spawned thread, so we cannot use it here +/// ``` +/// +/// `move` is also valid before an async block. +/// +/// ```rust +/// let capture = "hello".to_owned(); +/// let block = async move { +/// println!("rust says {capture} from async block"); +/// }; +/// ``` +/// +/// For more information on the `move` keyword, see the [closures][closure] section +/// of the Rust book or the [threads] section. +/// +/// [closure]: ../book/ch13-01-closures.html +/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads +mod move_keyword {} + +#[doc(keyword = "mut")] +// +/// A mutable variable, reference, or pointer. +/// +/// `mut` can be used in several situations. The first is mutable variables, +/// which can be used anywhere you can bind a value to a variable name. Some +/// examples: +/// +/// ```rust +/// // A mutable variable in the parameter list of a function. +/// fn foo(mut x: u8, y: u8) -> u8 { +/// x += y; +/// x +/// } +/// +/// // Modifying a mutable variable. +/// # #[allow(unused_assignments)] +/// let mut a = 5; +/// a = 6; +/// +/// assert_eq!(foo(3, 4), 7); +/// assert_eq!(a, 6); +/// ``` +/// +/// The second is mutable references. They can be created from `mut` variables +/// and must be unique: no other variables can have a mutable reference, nor a +/// shared reference. +/// +/// ```rust +/// // Taking a mutable reference. +/// fn push_two(v: &mut Vec) { +/// v.push(2); +/// } +/// +/// // A mutable reference cannot be taken to a non-mutable variable. +/// let mut v = vec![0, 1]; +/// // Passing a mutable reference. +/// push_two(&mut v); +/// +/// assert_eq!(v, vec![0, 1, 2]); +/// ``` +/// +/// ```rust,compile_fail,E0502 +/// let mut v = vec![0, 1]; +/// let mut_ref_v = &mut v; +/// # #[allow(unused)] +/// let ref_v = &v; +/// mut_ref_v.push(2); +/// ``` +/// +/// Mutable raw pointers work much like mutable references, with the added +/// possibility of not pointing to a valid object. The syntax is `*mut Type`. +/// +/// More information on mutable references and pointers can be found in the [Reference]. +/// +/// [Reference]: ../reference/types/pointer.html#mutable-references-mut +mod mut_keyword {} + +#[doc(keyword = "pub")] +// +/// Make an item visible to others. +/// +/// The keyword `pub` makes any module, function, or data structure accessible from inside +/// of external modules. The `pub` keyword may also be used in a `use` declaration to re-export +/// an identifier from a namespace. +/// +/// For more information on the `pub` keyword, please see the visibility section +/// of the [reference] and for some examples, see [Rust by Example]. +/// +/// [reference]:../reference/visibility-and-privacy.html?highlight=pub#visibility-and-privacy +/// [Rust by Example]:../rust-by-example/mod/visibility.html +mod pub_keyword {} + +#[doc(keyword = "ref")] +// +/// Bind by reference during pattern matching. +/// +/// `ref` annotates pattern bindings to make them borrow rather than move. +/// It is **not** a part of the pattern as far as matching is concerned: it does +/// not affect *whether* a value is matched, only *how* it is matched. +/// +/// By default, [`match`] statements consume all they can, which can sometimes +/// be a problem, when you don't really need the value to be moved and owned: +/// +/// ```compile_fail,E0382 +/// let maybe_name = Some(String::from("Alice")); +/// // The variable 'maybe_name' is consumed here ... +/// match maybe_name { +/// Some(n) => println!("Hello, {n}"), +/// _ => println!("Hello, world"), +/// } +/// // ... and is now unavailable. +/// println!("Hello again, {}", maybe_name.unwrap_or("world".into())); +/// ``` +/// +/// Using the `ref` keyword, the value is only borrowed, not moved, making it +/// available for use after the [`match`] statement: +/// +/// ``` +/// let maybe_name = Some(String::from("Alice")); +/// // Using `ref`, the value is borrowed, not moved ... +/// match maybe_name { +/// Some(ref n) => println!("Hello, {n}"), +/// _ => println!("Hello, world"), +/// } +/// // ... so it's available here! +/// println!("Hello again, {}", maybe_name.unwrap_or("world".into())); +/// ``` +/// +/// # `&` vs `ref` +/// +/// - `&` denotes that your pattern expects a reference to an object. Hence `&` +/// is a part of said pattern: `&Foo` matches different objects than `Foo` does. +/// +/// - `ref` indicates that you want a reference to an unpacked value. It is not +/// matched against: `Foo(ref foo)` matches the same objects as `Foo(foo)`. +/// +/// See also the [Reference] for more information. +/// +/// [`match`]: keyword.match.html +/// [Reference]: ../reference/patterns.html#identifier-patterns +mod ref_keyword {} + +#[doc(keyword = "return")] +// +/// Returns a value from a function. +/// +/// A `return` marks the end of an execution path in a function: +/// +/// ``` +/// fn foo() -> i32 { +/// return 3; +/// } +/// assert_eq!(foo(), 3); +/// ``` +/// +/// `return` is not needed when the returned value is the last expression in the +/// function. In this case the `;` is omitted: +/// +/// ``` +/// fn foo() -> i32 { +/// 3 +/// } +/// assert_eq!(foo(), 3); +/// ``` +/// +/// `return` returns from the function immediately (an "early return"): +/// +/// ```no_run +/// use std::fs::File; +/// use std::io::{Error, ErrorKind, Read, Result}; +/// +/// fn main() -> Result<()> { +/// let mut file = match File::open("foo.txt") { +/// Ok(f) => f, +/// Err(e) => return Err(e), +/// }; +/// +/// let mut contents = String::new(); +/// let size = match file.read_to_string(&mut contents) { +/// Ok(s) => s, +/// Err(e) => return Err(e), +/// }; +/// +/// if contents.contains("impossible!") { +/// return Err(Error::new(ErrorKind::Other, "oh no!")); +/// } +/// +/// if size > 9000 { +/// return Err(Error::new(ErrorKind::Other, "over 9000!")); +/// } +/// +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } +/// ``` +/// +/// Within [closures] and [`async`] blocks, `return` returns a value from within the closure or +/// `async` block, not from the parent function: +/// +/// ```rust +/// fn foo() -> i32 { +/// let closure = || { +/// return 5; +/// }; +/// +/// let future = async { +/// return 10; +/// }; +/// +/// return 15; +/// } +/// +/// assert_eq!(foo(), 15); +/// ``` +/// +/// [closures]: ../book/ch13-01-closures.html +/// [`async`]: ../std/keyword.async.html +mod return_keyword {} + +#[doc(keyword = "become")] +// +/// Perform a tail-call of a function. +/// +///
+/// +/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly. +///
+/// +/// When tail calling a function, instead of its stack frame being added to the +/// stack, the stack frame of the caller is directly replaced with the callee's. +/// This means that as long as a loop in a call graph only uses tail calls, the +/// stack growth will be bounded. +/// +/// This is useful for writing functional-style code (since it prevents recursion +/// from exhausting resources) or for code optimization (since a tail call +/// *might* be cheaper than a normal call, tail calls can be used in a similar +/// manner to computed goto). +/// +/// Example of using `become` to implement functional-style `fold`: +/// ``` +/// #![feature(explicit_tail_calls)] +/// #![expect(incomplete_features)] +/// +/// fn fold(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S { +/// match slice { +/// // without `become`, on big inputs this could easily overflow the +/// // stack. using a tail call guarantees that the stack will not grow unboundedly +/// [first, rest @ ..] => become fold(rest, f(init, *first), f), +/// [] => init, +/// } +/// } +/// ``` +/// +/// Compilers can already perform "tail call optimization" -- they can replace normal +/// calls with tail calls, although there are no guarantees that this will be done. +/// However, to perform TCO, the call needs to be the last thing that happens +/// in the functions and be returned from it. This requirement is often broken +/// by drop code for locals, which is run after computing the return expression: +/// +/// ``` +/// fn example() { +/// let string = "meow".to_owned(); +/// println!("{string}"); +/// return help(); // this is *not* the last thing that happens in `example`... +/// } +/// +/// // ... because it is desugared to this: +/// fn example_desugared() { +/// let string = "meow".to_owned(); +/// println!("{string}"); +/// let tmp = help(); +/// drop(string); +/// return tmp; +/// } +/// +/// fn help() {} +/// ``` +/// +/// For this reason, `become` also changes the drop order, such that locals are +/// dropped *before* evaluating the call. +/// +/// In order to guarantee that the compiler can perform a tail call, `become` +/// currently has these requirements: +/// 1. callee and caller must have the same ABI, arguments, and return type +/// 2. callee and caller must not have varargs +/// 3. caller must not be marked with `#[track_caller]` +/// - callee is allowed to be marked with `#[track_caller]` as otherwise +/// adding `#[track_caller]` would be a breaking change. if callee is +/// marked with `#[track_caller]` a tail call is not guaranteed. +/// 4. callee and caller cannot be a closure +/// (unless it's coerced to a function pointer) +/// +/// It is possible to tail-call a function pointer: +/// ``` +/// #![feature(explicit_tail_calls)] +/// #![expect(incomplete_features)] +/// +/// #[derive(Copy, Clone)] +/// enum Inst { Inc, Dec } +/// +/// fn dispatch(stream: &[Inst], state: u32) -> u32 { +/// const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement]; +/// match stream { +/// [inst, rest @ ..] => become TABLE[*inst as usize](rest, state), +/// [] => state, +/// } +/// } +/// +/// fn increment(stream: &[Inst], state: u32) -> u32 { +/// become dispatch(stream, state + 1) +/// } +/// +/// fn decrement(stream: &[Inst], state: u32) -> u32 { +/// become dispatch(stream, state - 1) +/// } +/// +/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc]; +/// assert_eq!(dispatch(program, 0), 2); +/// ``` +mod become_keyword {} + +#[doc(keyword = "self")] +// +/// The receiver of a method, or the current module. +/// +/// `self` is used in two situations: referencing the current module and marking +/// the receiver of a method. +/// +/// In paths, `self` can be used to refer to the current module, either in a +/// [`use`] statement or in a path to access an element: +/// +/// ``` +/// # #![allow(unused_imports)] +/// use std::io::{self, Read}; +/// ``` +/// +/// Is functionally the same as: +/// +/// ``` +/// # #![allow(unused_imports)] +/// use std::io; +/// use std::io::Read; +/// ``` +/// +/// Using `self` to access an element in the current module: +/// +/// ``` +/// # #![allow(dead_code)] +/// # fn main() {} +/// fn foo() {} +/// fn bar() { +/// self::foo() +/// } +/// ``` +/// +/// `self` as the current receiver for a method allows to omit the parameter +/// type most of the time. With the exception of this particularity, `self` is +/// used much like any other parameter: +/// +/// ``` +/// struct Foo(i32); +/// +/// impl Foo { +/// // No `self`. +/// fn new() -> Self { +/// Self(0) +/// } +/// +/// // Consuming `self`. +/// fn consume(self) -> Self { +/// Self(self.0 + 1) +/// } +/// +/// // Borrowing `self`. +/// fn borrow(&self) -> &i32 { +/// &self.0 +/// } +/// +/// // Borrowing `self` mutably. +/// fn borrow_mut(&mut self) -> &mut i32 { +/// &mut self.0 +/// } +/// } +/// +/// // This method must be called with a `Type::` prefix. +/// let foo = Foo::new(); +/// assert_eq!(foo.0, 0); +/// +/// // Those two calls produces the same result. +/// let foo = Foo::consume(foo); +/// assert_eq!(foo.0, 1); +/// let foo = foo.consume(); +/// assert_eq!(foo.0, 2); +/// +/// // Borrowing is handled automatically with the second syntax. +/// let borrow_1 = Foo::borrow(&foo); +/// let borrow_2 = foo.borrow(); +/// assert_eq!(borrow_1, borrow_2); +/// +/// // Borrowing mutably is handled automatically too with the second syntax. +/// let mut foo = Foo::new(); +/// *Foo::borrow_mut(&mut foo) += 1; +/// assert_eq!(foo.0, 1); +/// *foo.borrow_mut() += 1; +/// assert_eq!(foo.0, 2); +/// ``` +/// +/// Note that this automatic conversion when calling `foo.method()` is not +/// limited to the examples above. See the [Reference] for more information. +/// +/// [`use`]: keyword.use.html +/// [Reference]: ../reference/items/associated-items.html#methods +mod self_keyword {} + +// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can replace +// these two lines with `#[doc(keyword = "Self")]` and update `is_doc_keyword` in +// `CheckAttrVisitor`. +#[doc(alias = "Self")] +#[doc(keyword = "SelfTy")] +// +/// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type +/// definition. +/// +/// Within a type definition: +/// +/// ``` +/// # #![allow(dead_code)] +/// struct Node { +/// elem: i32, +/// // `Self` is a `Node` here. +/// next: Option>, +/// } +/// ``` +/// +/// In an [`impl`] block: +/// +/// ``` +/// struct Foo(i32); +/// +/// impl Foo { +/// fn new() -> Self { +/// Self(0) +/// } +/// } +/// +/// assert_eq!(Foo::new().0, Foo(0).0); +/// ``` +/// +/// Generic parameters are implicit with `Self`: +/// +/// ``` +/// # #![allow(dead_code)] +/// struct Wrap { +/// elem: T, +/// } +/// +/// impl Wrap { +/// fn new(elem: T) -> Self { +/// Self { elem } +/// } +/// } +/// ``` +/// +/// In a [`trait`] definition and related [`impl`] block: +/// +/// ``` +/// trait Example { +/// fn example() -> Self; +/// } +/// +/// struct Foo(i32); +/// +/// impl Example for Foo { +/// fn example() -> Self { +/// Self(42) +/// } +/// } +/// +/// assert_eq!(Foo::example().0, Foo(42).0); +/// ``` +/// +/// [`impl`]: keyword.impl.html +/// [`trait`]: keyword.trait.html +mod self_upper_keyword {} + +#[doc(keyword = "static")] +// +/// A static item is a value which is valid for the entire duration of your +/// program (a `'static` lifetime). +/// +/// On the surface, `static` items seem very similar to [`const`]s: both contain +/// a value, both require type annotations and both can only be initialized with +/// constant functions and values. However, `static`s are notably different in +/// that they represent a location in memory. That means that you can have +/// references to `static` items and potentially even modify them, making them +/// essentially global variables. +/// +/// Static items do not call [`drop`] at the end of the program. +/// +/// There are two types of `static` items: those declared in association with +/// the [`mut`] keyword and those without. +/// +/// Static items cannot be moved: +/// +/// ```rust,compile_fail,E0507 +/// static VEC: Vec = vec![]; +/// +/// fn move_vec(v: Vec) -> Vec { +/// v +/// } +/// +/// // This line causes an error +/// move_vec(VEC); +/// ``` +/// +/// # Simple `static`s +/// +/// Accessing non-[`mut`] `static` items is considered safe, but some +/// restrictions apply. Most notably, the type of a `static` value needs to +/// implement the [`Sync`] trait, ruling out interior mutability containers +/// like [`RefCell`]. See the [Reference] for more information. +/// +/// ```rust +/// static FOO: [i32; 5] = [1, 2, 3, 4, 5]; +/// +/// let r1 = &FOO as *const _; +/// let r2 = &FOO as *const _; +/// // With a strictly read-only static, references will have the same address +/// assert_eq!(r1, r2); +/// // A static item can be used just like a variable in many cases +/// println!("{FOO:?}"); +/// ``` +/// +/// # Mutable `static`s +/// +/// If a `static` item is declared with the [`mut`] keyword, then it is allowed +/// to be modified by the program. However, accessing mutable `static`s can +/// cause undefined behavior in a number of ways, for example due to data races +/// in a multithreaded context. As such, all accesses to mutable `static`s +/// require an [`unsafe`] block. +/// +/// When possible, it's often better to use a non-mutable `static` with an +/// interior mutable type such as [`Mutex`], [`OnceLock`], or an [atomic]. +/// +/// Despite their unsafety, mutable `static`s are necessary in many contexts: +/// they can be used to represent global state shared by the whole program or in +/// [`extern`] blocks to bind to variables from C libraries. +/// +/// In an [`extern`] block: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// unsafe extern "C" { +/// static mut ERROR_MESSAGE: *mut std::os::raw::c_char; +/// } +/// ``` +/// +/// Mutable `static`s, just like simple `static`s, have some restrictions that +/// apply to them. See the [Reference] for more information. +/// +/// [`const`]: keyword.const.html +/// [`extern`]: keyword.extern.html +/// [`mut`]: keyword.mut.html +/// [`unsafe`]: keyword.unsafe.html +/// [`Mutex`]: sync::Mutex +/// [`OnceLock`]: sync::OnceLock +/// [`RefCell`]: cell::RefCell +/// [atomic]: sync::atomic +/// [Reference]: ../reference/items/static-items.html +mod static_keyword {} + +#[doc(keyword = "struct")] +// +/// A type that is composed of other types. +/// +/// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit +/// structs. +/// +/// ```rust +/// struct Regular { +/// field1: f32, +/// field2: String, +/// pub field3: bool +/// } +/// +/// struct Tuple(u32, String); +/// +/// struct Unit; +/// ``` +/// +/// Regular structs are the most commonly used. Each field defined within them has a name and a +/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a +/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding +/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be +/// directly accessed and modified. +/// +/// Tuple structs are similar to regular structs, but its fields have no names. They are used like +/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax. For accessing +/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`, +/// etc, starting at zero. +/// +/// Unit structs are most commonly used as marker. They have a size of zero bytes, but unlike empty +/// enums they can be instantiated, making them isomorphic to the unit type `()`. Unit structs are +/// useful when you need to implement a trait on something, but don't need to store any data inside +/// it. +/// +/// # Instantiation +/// +/// Structs can be instantiated in different ways, all of which can be mixed and +/// matched as needed. The most common way to make a new struct is via a constructor method such as +/// `new()`, but when that isn't available (or you're writing the constructor itself), struct +/// literal syntax is used: +/// +/// ```rust +/// # struct Foo { field1: f32, field2: String, etc: bool } +/// let example = Foo { +/// field1: 42.0, +/// field2: "blah".to_string(), +/// etc: true, +/// }; +/// ``` +/// +/// It's only possible to directly instantiate a struct using struct literal syntax when all of its +/// fields are visible to you. +/// +/// There are a handful of shortcuts provided to make writing constructors more convenient, most +/// common of which is the Field Init shorthand. When there is a variable and a field of the same +/// name, the assignment can be simplified from `field: field` into simply `field`. The following +/// example of a hypothetical constructor demonstrates this: +/// +/// ```rust +/// struct User { +/// name: String, +/// admin: bool, +/// } +/// +/// impl User { +/// pub fn new(name: String) -> Self { +/// Self { +/// name, +/// admin: false, +/// } +/// } +/// } +/// ``` +/// +/// Another shortcut for struct instantiation is available, used when you need to make a new +/// struct that has the same values as most of a previous struct of the same type, called struct +/// update syntax: +/// +/// ```rust +/// # struct Foo { field1: String, field2: () } +/// # let thing = Foo { field1: "".to_string(), field2: () }; +/// let updated_thing = Foo { +/// field1: "a new value".to_string(), +/// ..thing +/// }; +/// ``` +/// +/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's +/// name as a prefix: `Foo(123, false, 0.1)`. +/// +/// Empty structs are instantiated with just their name, and don't need anything else. `let thing = +/// EmptyStruct;` +/// +/// # Style conventions +/// +/// Structs are always written in UpperCamelCase, with few exceptions. While the trailing comma on a +/// struct's list of fields can be omitted, it's usually kept for convenience in adding and +/// removing fields down the line. +/// +/// For more information on structs, take a look at the [Rust Book][book] or the +/// [Reference][reference]. +/// +/// [`PhantomData`]: marker::PhantomData +/// [book]: ../book/ch05-01-defining-structs.html +/// [reference]: ../reference/items/structs.html +mod struct_keyword {} + +#[doc(keyword = "super")] +// +/// The parent of the current [module]. +/// +/// ```rust +/// # #![allow(dead_code)] +/// # fn main() {} +/// mod a { +/// pub fn foo() {} +/// } +/// mod b { +/// pub fn foo() { +/// super::a::foo(); // call a's foo function +/// } +/// } +/// ``` +/// +/// It is also possible to use `super` multiple times: `super::super::foo`, +/// going up the ancestor chain. +/// +/// See the [Reference] for more information. +/// +/// [module]: ../reference/items/modules.html +/// [Reference]: ../reference/paths.html#super +mod super_keyword {} + +#[doc(keyword = "trait")] +// +/// A common interface for a group of types. +/// +/// A `trait` is like an interface that data types can implement. When a type +/// implements a trait it can be treated abstractly as that trait using generics +/// or trait objects. +/// +/// Traits can be made up of three varieties of associated items: +/// +/// - functions and methods +/// - types +/// - constants +/// +/// Traits may also contain additional type parameters. Those type parameters +/// or the trait itself can be constrained by other traits. +/// +/// Traits can serve as markers or carry other logical semantics that +/// aren't expressed through their items. When a type implements that +/// trait it is promising to uphold its contract. [`Send`] and [`Sync`] are two +/// such marker traits present in the standard library. +/// +/// See the [Reference][Ref-Traits] for a lot more information on traits. +/// +/// # Examples +/// +/// Traits are declared using the `trait` keyword. Types can implement them +/// using [`impl`] `Trait` [`for`] `Type`: +/// +/// ```rust +/// trait Zero { +/// const ZERO: Self; +/// fn is_zero(&self) -> bool; +/// } +/// +/// impl Zero for i32 { +/// const ZERO: Self = 0; +/// +/// fn is_zero(&self) -> bool { +/// *self == Self::ZERO +/// } +/// } +/// +/// assert_eq!(i32::ZERO, 0); +/// assert!(i32::ZERO.is_zero()); +/// assert!(!4.is_zero()); +/// ``` +/// +/// With an associated type: +/// +/// ```rust +/// trait Builder { +/// type Built; +/// +/// fn build(&self) -> Self::Built; +/// } +/// ``` +/// +/// Traits can be generic, with constraints or without: +/// +/// ```rust +/// trait MaybeFrom { +/// fn maybe_from(value: T) -> Option +/// where +/// Self: Sized; +/// } +/// ``` +/// +/// Traits can build upon the requirements of other traits. In the example +/// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**: +/// +/// ```rust +/// trait ThreeIterator: Iterator { +/// fn next_three(&mut self) -> Option<[Self::Item; 3]>; +/// } +/// ``` +/// +/// Traits can be used in functions, as parameters: +/// +/// ```rust +/// # #![allow(dead_code)] +/// fn debug_iter(it: I) where I::Item: std::fmt::Debug { +/// for elem in it { +/// println!("{elem:#?}"); +/// } +/// } +/// +/// // u8_len_1, u8_len_2 and u8_len_3 are equivalent +/// +/// fn u8_len_1(val: impl Into>) -> usize { +/// val.into().len() +/// } +/// +/// fn u8_len_2>>(val: T) -> usize { +/// val.into().len() +/// } +/// +/// fn u8_len_3(val: T) -> usize +/// where +/// T: Into>, +/// { +/// val.into().len() +/// } +/// ``` +/// +/// Or as return types: +/// +/// ```rust +/// # #![allow(dead_code)] +/// fn from_zero_to(v: u8) -> impl Iterator { +/// (0..v).into_iter() +/// } +/// ``` +/// +/// The use of the [`impl`] keyword in this position allows the function writer +/// to hide the concrete type as an implementation detail which can change +/// without breaking user's code. +/// +/// # Trait objects +/// +/// A *trait object* is an opaque value of another type that implements a set of +/// traits. A trait object implements all specified traits as well as their +/// supertraits (if any). +/// +/// The syntax is the following: `dyn BaseTrait + AutoTrait1 + ... AutoTraitN`. +/// Only one `BaseTrait` can be used so this will not compile: +/// +/// ```rust,compile_fail,E0225 +/// trait A {} +/// trait B {} +/// +/// let _: Box; +/// ``` +/// +/// Neither will this, which is a syntax error: +/// +/// ```rust,compile_fail +/// trait A {} +/// trait B {} +/// +/// let _: Box; +/// ``` +/// +/// On the other hand, this is correct: +/// +/// ```rust +/// trait A {} +/// +/// let _: Box; +/// ``` +/// +/// The [Reference][Ref-Trait-Objects] has more information about trait objects, +/// their limitations and the differences between editions. +/// +/// # Unsafe traits +/// +/// Some traits may be unsafe to implement. Using the [`unsafe`] keyword in +/// front of the trait's declaration is used to mark this: +/// +/// ```rust +/// unsafe trait UnsafeTrait {} +/// +/// unsafe impl UnsafeTrait for i32 {} +/// ``` +/// +/// # Differences between the 2015 and 2018 editions +/// +/// In the 2015 edition the parameters pattern was not needed for traits: +/// +/// ```rust,edition2015 +/// # #![allow(anonymous_parameters)] +/// trait Tr { +/// fn f(i32); +/// } +/// ``` +/// +/// This behavior is no longer valid in edition 2018. +/// +/// [`for`]: keyword.for.html +/// [`impl`]: keyword.impl.html +/// [`unsafe`]: keyword.unsafe.html +/// [Ref-Traits]: ../reference/items/traits.html +/// [Ref-Trait-Objects]: ../reference/types/trait-object.html +mod trait_keyword {} + +#[doc(keyword = "true")] +// +/// A value of type [`bool`] representing logical **true**. +/// +/// Logically `true` is not equal to [`false`]. +/// +/// ## Control structures that check for **true** +/// +/// Several of Rust's control structures will check for a `bool` condition evaluating to **true**. +/// +/// * The condition in an [`if`] expression must be of type `bool`. +/// Whenever that condition evaluates to **true**, the `if` expression takes +/// on the value of the first block. If however, the condition evaluates +/// to `false`, the expression takes on value of the `else` block if there is one. +/// +/// * [`while`] is another control flow construct expecting a `bool`-typed condition. +/// As long as the condition evaluates to **true**, the `while` loop will continually +/// evaluate its associated block. +/// +/// * [`match`] arms can have guard clauses on them. +/// +/// [`if`]: keyword.if.html +/// [`while`]: keyword.while.html +/// [`match`]: ../reference/expressions/match-expr.html#match-guards +/// [`false`]: keyword.false.html +mod true_keyword {} + +#[doc(keyword = "type")] +// +/// Define an [alias] for an existing type. +/// +/// The syntax is `type Name = ExistingType;`. +/// +/// # Examples +/// +/// `type` does **not** create a new type: +/// +/// ```rust +/// type Meters = u32; +/// type Kilograms = u32; +/// +/// let m: Meters = 3; +/// let k: Kilograms = 3; +/// +/// assert_eq!(m, k); +/// ``` +/// +/// A type can be generic: +/// +/// ```rust +/// # use std::sync::{Arc, Mutex}; +/// type ArcMutex = Arc>; +/// ``` +/// +/// In traits, `type` is used to declare an [associated type]: +/// +/// ```rust +/// trait Iterator { +/// // associated type declaration +/// type Item; +/// fn next(&mut self) -> Option; +/// } +/// +/// struct Once(Option); +/// +/// impl Iterator for Once { +/// // associated type definition +/// type Item = T; +/// fn next(&mut self) -> Option { +/// self.0.take() +/// } +/// } +/// ``` +/// +/// [`trait`]: keyword.trait.html +/// [associated type]: ../reference/items/associated-items.html#associated-types +/// [alias]: ../reference/items/type-aliases.html +mod type_keyword {} + +#[doc(keyword = "unsafe")] +// +/// Code or interfaces whose [memory safety] cannot be verified by the type +/// system. +/// +/// The `unsafe` keyword has two uses: +/// - to declare the existence of contracts the compiler can't check (`unsafe fn` and `unsafe +/// trait`), +/// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe +/// {}` and `unsafe impl`, but also `unsafe fn` -- see below). +/// +/// # Unsafe abilities +/// +/// **No matter what, Safe Rust can't cause Undefined Behavior**. This is +/// referred to as [soundness]: a well-typed program actually has the desired +/// properties. The [Nomicon][nomicon-soundness] has a more detailed explanation +/// on the subject. +/// +/// To ensure soundness, Safe Rust is restricted enough that it can be +/// automatically checked. Sometimes, however, it is necessary to write code +/// that is correct for reasons which are too clever for the compiler to +/// understand. In those cases, you need to use Unsafe Rust. +/// +/// Here are the abilities Unsafe Rust has in addition to Safe Rust: +/// +/// - Dereference [raw pointers] +/// - Implement `unsafe` [`trait`]s +/// - Call `unsafe` functions +/// - Mutate [`static`]s (including [`extern`]al ones) +/// - Access fields of [`union`]s +/// +/// However, this extra power comes with extra responsibilities: it is now up to +/// you to ensure soundness. The `unsafe` keyword helps by clearly marking the +/// pieces of code that need to worry about this. +/// +/// ## The different meanings of `unsafe` +/// +/// Not all uses of `unsafe` are equivalent: some are here to mark the existence +/// of a contract the programmer must check, others are to say "I have checked +/// the contract, go ahead and do this". The following +/// [discussion on Rust Internals] has more in-depth explanations about this but +/// here is a summary of the main points: +/// +/// - `unsafe fn`: calling this function means abiding by a contract the +/// compiler cannot enforce. +/// - `unsafe trait`: implementing the [`trait`] means abiding by a +/// contract the compiler cannot enforce. +/// - `unsafe {}`: the contract necessary to call the operations inside the +/// block has been checked by the programmer and is guaranteed to be respected. +/// - `unsafe impl`: the contract necessary to implement the trait has been +/// checked by the programmer and is guaranteed to be respected. +/// +/// See the [Rustonomicon] and the [Reference] for more information. +/// +/// # Examples +/// +/// ## Marking elements as `unsafe` +/// +/// `unsafe` can be used on functions. Note that functions and statics declared +/// in [`extern`] blocks are implicitly marked as `unsafe` (but not functions +/// declared as `extern "something" fn ...`). Mutable statics are always unsafe, +/// wherever they are declared. Methods can also be declared as `unsafe`: +/// +/// ```rust +/// # #![allow(dead_code)] +/// static mut FOO: &str = "hello"; +/// +/// unsafe fn unsafe_fn() {} +/// +/// unsafe extern "C" { +/// fn unsafe_extern_fn(); +/// static BAR: *mut u32; +/// } +/// +/// trait SafeTraitWithUnsafeMethod { +/// unsafe fn unsafe_method(&self); +/// } +/// +/// struct S; +/// +/// impl S { +/// unsafe fn unsafe_method_on_struct() {} +/// } +/// ``` +/// +/// Traits can also be declared as `unsafe`: +/// +/// ```rust +/// unsafe trait UnsafeTrait {} +/// ``` +/// +/// Since `unsafe fn` and `unsafe trait` indicate that there is a safety +/// contract that the compiler cannot enforce, documenting it is important. The +/// standard library has many examples of this, like the following which is an +/// extract from [`Vec::set_len`]. The `# Safety` section explains the contract +/// that must be fulfilled to safely call the function. +/// +/// ```rust,ignore (stub-to-show-doc-example) +/// /// Forces the length of the vector to `new_len`. +/// /// +/// /// This is a low-level operation that maintains none of the normal +/// /// invariants of the type. Normally changing the length of a vector +/// /// is done using one of the safe operations instead, such as +/// /// `truncate`, `resize`, `extend`, or `clear`. +/// /// +/// /// # Safety +/// /// +/// /// - `new_len` must be less than or equal to `capacity()`. +/// /// - The elements at `old_len..new_len` must be initialized. +/// pub unsafe fn set_len(&mut self, new_len: usize) +/// ``` +/// +/// ## Using `unsafe {}` blocks and `impl`s +/// +/// Performing `unsafe` operations requires an `unsafe {}` block: +/// +/// ```rust +/// # #![allow(dead_code)] +/// #![deny(unsafe_op_in_unsafe_fn)] +/// +/// /// Dereference the given pointer. +/// /// +/// /// # Safety +/// /// +/// /// `ptr` must be aligned and must not be dangling. +/// unsafe fn deref_unchecked(ptr: *const i32) -> i32 { +/// // SAFETY: the caller is required to ensure that `ptr` is aligned and dereferenceable. +/// unsafe { *ptr } +/// } +/// +/// let a = 3; +/// let b = &a as *const _; +/// // SAFETY: `a` has not been dropped and references are always aligned, +/// // so `b` is a valid address. +/// unsafe { assert_eq!(*b, deref_unchecked(b)); }; +/// ``` +/// +/// ## `unsafe` and traits +/// +/// The interactions of `unsafe` and traits can be surprising, so let us contrast the +/// two combinations of safe `fn` in `unsafe trait` and `unsafe fn` in safe trait using two +/// examples: +/// +/// ```rust +/// /// # Safety +/// /// +/// /// `make_even` must return an even number. +/// unsafe trait MakeEven { +/// fn make_even(&self) -> i32; +/// } +/// +/// // SAFETY: Our `make_even` always returns something even. +/// unsafe impl MakeEven for i32 { +/// fn make_even(&self) -> i32 { +/// self << 1 +/// } +/// } +/// +/// fn use_make_even(x: impl MakeEven) { +/// if x.make_even() % 2 == 1 { +/// // SAFETY: this can never happen, because all `MakeEven` implementations +/// // ensure that `make_even` returns something even. +/// unsafe { std::hint::unreachable_unchecked() }; +/// } +/// } +/// ``` +/// +/// Note how the safety contract of the trait is upheld by the implementation, and is itself used to +/// uphold the safety contract of the unsafe function `unreachable_unchecked` called by +/// `use_make_even`. `make_even` itself is a safe function because its *callers* do not have to +/// worry about any contract, only the *implementation* of `MakeEven` is required to uphold a +/// certain contract. `use_make_even` is safe because it can use the promise made by `MakeEven` +/// implementations to uphold the safety contract of the `unsafe fn unreachable_unchecked` it calls. +/// +/// It is also possible to have `unsafe fn` in a regular safe `trait`: +/// +/// ```rust +/// # #![feature(never_type)] +/// #![deny(unsafe_op_in_unsafe_fn)] +/// +/// trait Indexable { +/// const LEN: usize; +/// +/// /// # Safety +/// /// +/// /// The caller must ensure that `idx < LEN`. +/// unsafe fn idx_unchecked(&self, idx: usize) -> i32; +/// } +/// +/// // The implementation for `i32` doesn't need to do any contract reasoning. +/// impl Indexable for i32 { +/// const LEN: usize = 1; +/// +/// /// See `Indexable` for the safety contract. +/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { +/// debug_assert_eq!(idx, 0); +/// *self +/// } +/// } +/// +/// // The implementation for arrays exploits the function contract to +/// // make use of `get_unchecked` on slices and avoid a run-time check. +/// impl Indexable for [i32; 42] { +/// const LEN: usize = 42; +/// +/// /// See `Indexable` for the safety contract. +/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { +/// // SAFETY: As per this trait's documentation, the caller ensures +/// // that `idx < 42`. +/// unsafe { *self.get_unchecked(idx) } +/// } +/// } +/// +/// // The implementation for the never type declares a length of 0, +/// // which means `idx_unchecked` can never be called. +/// impl Indexable for ! { +/// const LEN: usize = 0; +/// +/// /// See `Indexable` for the safety contract. +/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { +/// // SAFETY: As per this trait's documentation, the caller ensures +/// // that `idx < 0`, which is impossible, so this is dead code. +/// unsafe { std::hint::unreachable_unchecked() } +/// } +/// } +/// +/// fn use_indexable(x: I, idx: usize) -> i32 { +/// if idx < I::LEN { +/// // SAFETY: We have checked that `idx < I::LEN`. +/// unsafe { x.idx_unchecked(idx) } +/// } else { +/// panic!("index out-of-bounds") +/// } +/// } +/// ``` +/// +/// This time, `use_indexable` is safe because it uses a run-time check to discharge the safety +/// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing +/// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation +/// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation +/// to contend with. Of course, the implementation may choose to call other unsafe operations, and +/// then it needs an `unsafe` *block* to indicate it discharged the proof obligations of its +/// callees. For that purpose it can make use of the contract that all its callers must uphold -- +/// the fact that `idx < LEN`. +/// +/// Note that unlike normal `unsafe fn`, an `unsafe fn` in a trait implementation does not get to +/// just pick an arbitrary safety contract! It *has* to use the safety contract defined by the trait +/// (or one with weaker preconditions). +/// +/// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond +/// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare +/// that some of its functions have *postconditions* that go beyond those encoded in the return type +/// (such as returning an even integer). If a trait needs a function with both extra precondition +/// and extra postcondition, then it needs an `unsafe fn` in an `unsafe trait`. +/// +/// [`extern`]: keyword.extern.html +/// [`trait`]: keyword.trait.html +/// [`static`]: keyword.static.html +/// [`union`]: keyword.union.html +/// [`impl`]: keyword.impl.html +/// [raw pointers]: ../reference/types/pointer.html +/// [memory safety]: ../book/ch19-01-unsafe-rust.html +/// [Rustonomicon]: ../nomicon/index.html +/// [nomicon-soundness]: ../nomicon/safe-unsafe-meaning.html +/// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library +/// [Reference]: ../reference/unsafety.html +/// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696 +mod unsafe_keyword {} + +#[doc(keyword = "use")] +// +/// Import or rename items from other crates or modules, use values under ergonomic clones +/// semantic, or specify precise capturing with `use<..>`. +/// +/// ## Importing items +/// +/// The `use` keyword is employed to shorten the path required to refer to a module item. +/// The keyword may appear in modules, blocks, and even functions, typically at the top. +/// +/// The most basic usage of the keyword is `use path::to::item;`, +/// though a number of convenient shortcuts are supported: +/// +/// * Simultaneously binding a list of paths with a common prefix, +/// using the glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};` +/// * Simultaneously binding a list of paths with a common prefix and their common parent module, +/// using the [`self`] keyword, such as `use a::b::{self, c, d::e};` +/// * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. +/// This can also be used with the last two features: `use a::b::{self as ab, c as abc}`. +/// * Binding all paths matching a given prefix, +/// using the asterisk wildcard syntax `use a::b::*;`. +/// * Nesting groups of the previous features multiple times, +/// such as `use a::b::{self as ab, c, d::{*, e::f}};` +/// * Reexporting with visibility modifiers such as `pub use a::b;` +/// * Importing with `_` to only import the methods of a trait without binding it to a name +/// (to avoid conflict for example): `use ::std::io::Read as _;`. +/// +/// Using path qualifiers like [`crate`], [`super`] or [`self`] is supported: `use crate::a::b;`. +/// +/// Note that when the wildcard `*` is used on a type, it does not import its methods (though +/// for `enum`s it imports the variants, as shown in the example below). +/// +/// ```compile_fail,edition2018 +/// enum ExampleEnum { +/// VariantA, +/// VariantB, +/// } +/// +/// impl ExampleEnum { +/// fn new() -> Self { +/// Self::VariantA +/// } +/// } +/// +/// use ExampleEnum::*; +/// +/// // Compiles. +/// let _ = VariantA; +/// +/// // Does not compile! +/// let n = new(); +/// ``` +/// +/// For more information on `use` and paths in general, see the [Reference][ref-use-decls]. +/// +/// The differences about paths and the `use` keyword between the 2015 and 2018 editions +/// can also be found in the [Reference][ref-use-decls]. +/// +/// ## Precise capturing +/// +/// The `use<..>` syntax is used within certain `impl Trait` bounds to control which generic +/// parameters are captured. This is important for return-position `impl Trait` (RPIT) types, +/// as it affects borrow checking by controlling which generic parameters can be used in the +/// hidden type. +/// +/// For example, the following function demonstrates an error without precise capturing in +/// Rust 2021 and earlier editions: +/// +/// ```rust,compile_fail,edition2021 +/// fn f(x: &()) -> impl Sized { x } +/// ``` +/// +/// By using `use<'_>` for precise capturing, it can be resolved: +/// +/// ```rust +/// fn f(x: &()) -> impl Sized + use<'_> { x } +/// ``` +/// +/// This syntax specifies that the elided lifetime be captured and therefore available for +/// use in the hidden type. +/// +/// In Rust 2024, opaque types automatically capture all lifetime parameters in scope. +/// `use<..>` syntax serves as an important way of opting-out of that default. +/// +/// For more details about precise capturing, see the [Reference][ref-impl-trait]. +/// +/// ## Ergonomic clones +/// +/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the +/// value implements `UseCloned` or moving it otherwise. +/// +/// [`crate`]: keyword.crate.html +/// [`self`]: keyword.self.html +/// [`super`]: keyword.super.html +/// [ref-use-decls]: ../reference/items/use-declarations.html +/// [ref-impl-trait]: ../reference/types/impl-trait.html +mod use_keyword {} + +#[doc(keyword = "where")] +// +/// Add constraints that must be upheld to use an item. +/// +/// `where` allows specifying constraints on lifetime and generic parameters. +/// The [RFC] introducing `where` contains detailed information about the +/// keyword. +/// +/// # Examples +/// +/// `where` can be used for constraints with traits: +/// +/// ```rust +/// fn new() -> T { +/// T::default() +/// } +/// +/// fn new_where() -> T +/// where +/// T: Default, +/// { +/// T::default() +/// } +/// +/// assert_eq!(0.0, new()); +/// assert_eq!(0.0, new_where()); +/// +/// assert_eq!(0, new()); +/// assert_eq!(0, new_where()); +/// ``` +/// +/// `where` can also be used for lifetimes. +/// +/// This compiles because `longer` outlives `shorter`, thus the constraint is +/// respected: +/// +/// ```rust +/// fn select<'short, 'long>(s1: &'short str, s2: &'long str, second: bool) -> &'short str +/// where +/// 'long: 'short, +/// { +/// if second { s2 } else { s1 } +/// } +/// +/// let outer = String::from("Long living ref"); +/// let longer = &outer; +/// { +/// let inner = String::from("Short living ref"); +/// let shorter = &inner; +/// +/// assert_eq!(select(shorter, longer, false), shorter); +/// assert_eq!(select(shorter, longer, true), longer); +/// } +/// ``` +/// +/// On the other hand, this will not compile because the `where 'b: 'a` clause +/// is missing: the `'b` lifetime is not known to live at least as long as `'a` +/// which means this function cannot ensure it always returns a valid reference: +/// +/// ```rust,compile_fail +/// fn select<'a, 'b>(s1: &'a str, s2: &'b str, second: bool) -> &'a str +/// { +/// if second { s2 } else { s1 } +/// } +/// ``` +/// +/// `where` can also be used to express more complicated constraints that cannot +/// be written with the `` syntax: +/// +/// ```rust +/// fn first_or_default(mut i: I) -> I::Item +/// where +/// I: Iterator, +/// I::Item: Default, +/// { +/// i.next().unwrap_or_else(I::Item::default) +/// } +/// +/// assert_eq!(first_or_default([1, 2, 3].into_iter()), 1); +/// assert_eq!(first_or_default(Vec::::new().into_iter()), 0); +/// ``` +/// +/// `where` is available anywhere generic and lifetime parameters are available, +/// as can be seen with the [`Cow`](crate::borrow::Cow) type from the standard +/// library: +/// +/// ```rust +/// # #![allow(dead_code)] +/// pub enum Cow<'a, B> +/// where +/// B: ToOwned + ?Sized, +/// { +/// Borrowed(&'a B), +/// Owned(::Owned), +/// } +/// ``` +/// +/// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md +mod where_keyword {} + +#[doc(keyword = "while")] +// +/// Loop while a condition is upheld. +/// +/// A `while` expression is used for predicate loops. The `while` expression runs the conditional +/// expression before running the loop body, then runs the loop body if the conditional +/// expression evaluates to `true`, or exits the loop otherwise. +/// +/// ```rust +/// let mut counter = 0; +/// +/// while counter < 10 { +/// println!("{counter}"); +/// counter += 1; +/// } +/// ``` +/// +/// Like the [`for`] expression, we can use `break` and `continue`. A `while` expression +/// cannot break with a value and always evaluates to `()` unlike [`loop`]. +/// +/// ```rust +/// let mut i = 1; +/// +/// while i < 100 { +/// i *= 2; +/// if i == 64 { +/// break; // Exit when `i` is 64. +/// } +/// } +/// ``` +/// +/// As `if` expressions have their pattern matching variant in `if let`, so too do `while` +/// expressions with `while let`. The `while let` expression matches the pattern against the +/// expression, then runs the loop body if pattern matching succeeds, or exits the loop otherwise. +/// We can use `break` and `continue` in `while let` expressions just like in `while`. +/// +/// ```rust +/// let mut counter = Some(0); +/// +/// while let Some(i) = counter { +/// if i == 10 { +/// counter = None; +/// } else { +/// println!("{i}"); +/// counter = Some (i + 1); +/// } +/// } +/// ``` +/// +/// For more information on `while` and loops in general, see the [reference]. +/// +/// See also, [`for`], [`loop`]. +/// +/// [`for`]: keyword.for.html +/// [`loop`]: keyword.loop.html +/// [reference]: ../reference/expressions/loop-expr.html#predicate-loops +mod while_keyword {} + +// 2018 Edition keywords + +#[doc(alias = "promise")] +#[doc(keyword = "async")] +// +/// Returns a [`Future`] instead of blocking the current thread. +/// +/// Use `async` in front of `fn`, `closure`, or a `block` to turn the marked code into a `Future`. +/// As such the code will not be run immediately, but will only be evaluated when the returned +/// future is [`.await`]ed. +/// +/// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. +/// +/// ## Control Flow +/// [`return`] statements and [`?`][try operator] operators within `async` blocks do not cause +/// a return from the parent function; rather, they cause the `Future` returned by the block to +/// return with that value. +/// +/// For example, the following Rust function will return `5`, causing `x` to take the [`!` type][never type]: +/// ```rust +/// #[expect(unused_variables)] +/// fn example() -> i32 { +/// let x = { +/// return 5; +/// }; +/// } +/// ``` +/// In contrast, the following asynchronous function assigns a `Future` to `x`, and +/// only returns `5` when `x` is `.await`ed: +/// ```rust +/// async fn example() -> i32 { +/// let x = async { +/// return 5; +/// }; +/// +/// x.await +/// } +/// ``` +/// Code using `?` behaves similarly - it causes the `async` block to return a [`Result`] without +/// affecting the parent function. +/// +/// Note that you cannot use `break` or `continue` from within an `async` block to affect the +/// control flow of a loop in the parent function. +/// +/// Control flow in `async` blocks is documented further in the [async book][async book blocks]. +/// +/// ## Editions +/// +/// `async` is a keyword from the 2018 edition onwards. +/// +/// It is available for use in stable Rust from version 1.39 onwards. +/// +/// [`Future`]: future::Future +/// [`.await`]: ../std/keyword.await.html +/// [async book]: https://rust-lang.github.io/async-book/ +/// [`return`]: ../std/keyword.return.html +/// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try +/// [never type]: ../reference/types/never.html +/// [`Result`]: result::Result +/// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks +mod async_keyword {} + +#[doc(keyword = "await")] +// +/// Suspend execution until the result of a [`Future`] is ready. +/// +/// `.await`ing a future will suspend the current function's execution until the executor +/// has run the future to completion. +/// +/// Read the [async book] for details on how [`async`]/`await` and executors work. +/// +/// ## Editions +/// +/// `await` is a keyword from the 2018 edition onwards. +/// +/// It is available for use in stable Rust from version 1.39 onwards. +/// +/// [`Future`]: future::Future +/// [async book]: https://rust-lang.github.io/async-book/ +/// [`async`]: ../std/keyword.async.html +mod await_keyword {} + +#[doc(keyword = "dyn")] +// +/// `dyn` is a prefix of a [trait object]'s type. +/// +/// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait` +/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1]. +/// +/// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that +/// is being passed. That is, the type has been [erased]. +/// As such, a `dyn Trait` reference contains _two_ pointers. +/// One pointer goes to the data (e.g., an instance of a struct). +/// Another pointer goes to a map of method call names to function pointers +/// (known as a virtual method table or vtable). +/// +/// At run-time, when a method needs to be called on the `dyn Trait`, the vtable is consulted to get +/// the function pointer and then that function pointer is called. +/// +/// See the Reference for more information on [trait objects][ref-trait-obj] +/// and [dyn compatibility][ref-dyn-compat]. +/// +/// ## Trade-offs +/// +/// The above indirection is the additional runtime cost of calling a function on a `dyn Trait`. +/// Methods called by dynamic dispatch generally cannot be inlined by the compiler. +/// +/// However, `dyn Trait` is likely to produce smaller code than `impl Trait` / generic parameters as +/// the method won't be duplicated for each concrete type. +/// +/// [trait object]: ../book/ch17-02-trait-objects.html +/// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch +/// [ref-trait-obj]: ../reference/types/trait-object.html +/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility +/// [erased]: https://en.wikipedia.org/wiki/Type_erasure +/// [^1]: Formerly known as *object safe*. +mod dyn_keyword {} + +#[doc(keyword = "union")] +// +/// The [Rust equivalent of a C-style union][union]. +/// +/// A `union` looks like a [`struct`] in terms of declaration, but all of its +/// fields exist in the same memory, superimposed over one another. For instance, +/// if we wanted some bits in memory that we sometimes interpret as a `u32` and +/// sometimes as an `f32`, we could write: +/// +/// ```rust +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let mut u = IntOrFloat { f: 1.0 }; +/// // Reading the fields of a union is always unsafe +/// assert_eq!(unsafe { u.i }, 1065353216); +/// // Updating through any of the field will modify all of them +/// u.i = 1073741824; +/// assert_eq!(unsafe { u.f }, 2.0); +/// ``` +/// +/// # Matching on unions +/// +/// It is possible to use pattern matching on `union`s. A single field name must +/// be used and it must match the name of one of the `union`'s field. +/// Like reading from a `union`, pattern matching on a `union` requires `unsafe`. +/// +/// ```rust +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let u = IntOrFloat { f: 1.0 }; +/// +/// unsafe { +/// match u { +/// IntOrFloat { i: 10 } => println!("Found exactly ten!"), +/// // Matching the field `f` provides an `f32`. +/// IntOrFloat { f } => println!("Found f = {f} !"), +/// } +/// } +/// ``` +/// +/// # References to union fields +/// +/// All fields in a `union` are all at the same place in memory which means +/// borrowing one borrows the entire `union`, for the same lifetime: +/// +/// ```rust,compile_fail,E0502 +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let mut u = IntOrFloat { f: 1.0 }; +/// +/// let f = unsafe { &u.f }; +/// // This will not compile because the field has already been borrowed, even +/// // if only immutably +/// let i = unsafe { &mut u.i }; +/// +/// *i = 10; +/// println!("f = {f} and i = {i}"); +/// ``` +/// +/// See the [Reference][union] for more information on `union`s. +/// +/// [`struct`]: keyword.struct.html +/// [union]: ../reference/items/unions.html +mod union_keyword {} diff --git a/crates/std/src/lib.rs b/crates/std/src/lib.rs index cf236d9..a434746 100644 --- a/crates/std/src/lib.rs +++ b/crates/std/src/lib.rs @@ -9,6 +9,7 @@ #![allow(unused_lifetimes)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] +#![allow(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] @@ -265,7 +266,7 @@ pub use alloc_crate::vec; pub use core::{ assert, cfg, column, compile_error, concat, const_format_args, env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env, - stringify, trace_macros, + stringify, trace_macros, unimplemented }; #[rustc_std_internal_symbol] @@ -276,7 +277,6 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn core::panic::PanicPayload) - pub mod ffi; pub mod hash; pub mod io; -// pub mod fs; pub mod error; pub mod num; pub mod path; @@ -285,17 +285,25 @@ pub mod process; #[macro_use] pub mod rt; pub mod alloc; +pub mod ascii; +pub mod backtrace; pub mod bstr; pub mod collections; pub mod env; +pub mod fs; +pub mod keyword_docs; +pub mod macros; pub mod os; pub mod panic; pub mod panicking; +pub mod pat; pub mod sync; pub mod sys; pub mod thread; pub mod time; -pub use backtrace_rs; + +#[path = "../crates/backtrace-rs/src/lib.rs"] +mod backtrace_rs; #[prelude_import] #[allow(unused_imports)] @@ -310,23 +318,23 @@ mod sealed { pub trait Sealed {} } -pub use shared::fs; +pub use shared::fs as other_fs; pub use shared::syscall; -#[macro_export] -macro_rules! print { - ($($args:expr),*) => { - $crate::syscall::write_string_temp(&format!($($args),*)) - }; -} -#[macro_export] -macro_rules! println { - () => { - $crate::print!(""); - // $crate::print!("\n\r"); - }; - ($($args:expr),*) => { - $crate::print!($($args),*); - // $crate::println!(); - }; -} +// #[macro_export] +// macro_rules! print { +// ($($args:expr),*) => { +// $crate::syscall::write_string_temp(&format!($($args),*)) +// }; +// } +// #[macro_export] +// macro_rules! println { +// () => { +// $crate::print!(""); +// // $crate::print!("\n\r"); +// }; +// ($($args:expr),*) => { +// $crate::print!($($args),*); +// // $crate::println!(); +// }; +// } diff --git a/crates/std/src/macros.rs b/crates/std/src/macros.rs new file mode 100644 index 0000000..9618cdc --- /dev/null +++ b/crates/std/src/macros.rs @@ -0,0 +1,416 @@ +//! Standard library macros +//! +//! This module contains a set of macros which are exported from the standard +//! library. Each macro is available for use when linking against the standard +//! library. +// ignore-tidy-dbg + + // todo retreive docs +#[macro_export] +#[rustc_builtin_macro(std_panic)] +#[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable(edition_panic)] +#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")] +macro_rules! panic { + // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` + // depending on the edition of the caller. + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} + +/// Prints to the standard output. +/// +/// Equivalent to the [`println!`] macro except that a newline is not printed at +/// the end of the message. +/// +/// Note that stdout is frequently line-buffered by default so it may be +/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted +/// immediately. +/// +/// The `print!` macro will lock the standard output on each call. If you call +/// `print!` within a hot loop, this behavior may be the bottleneck of the loop. +/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]: +/// ``` +/// use std::io::{stdout, Write}; +/// +/// let mut lock = stdout().lock(); +/// write!(lock, "hello world").unwrap(); +/// ``` +/// +/// Use `print!` only for the primary output of your program. Use +/// [`eprint!`] instead to print error and progress messages. +/// +/// See the formatting documentation in [`std::fmt`](crate::fmt) +/// for details of the macro argument syntax. +/// +/// [flush]: crate::io::Write::flush +/// [`println!`]: crate::println +/// [`eprint!`]: crate::eprint +/// [lock]: crate::io::Stdout +/// +/// # Panics +/// +/// Panics if writing to `io::stdout()` fails. +/// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// use std::io::{self, Write}; +/// +/// print!("this "); +/// print!("will "); +/// print!("be "); +/// print!("on "); +/// print!("the "); +/// print!("same "); +/// print!("line "); +/// +/// io::stdout().flush().unwrap(); +/// +/// print!("this string has a newline, why not choose println! instead?\n"); +/// +/// io::stdout().flush().unwrap(); +/// ``` +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")] +#[allow_internal_unstable(print_internals)] +macro_rules! print { + ($($arg:tt)*) => {{ + $crate::io::_print($crate::format_args!($($arg)*)); + }}; +} + +/// Prints to the standard output, with a newline. +/// +/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone +/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)). +/// +/// This macro uses the same syntax as [`format!`], but writes to the standard output instead. +/// See [`std::fmt`] for more information. +/// +/// The `println!` macro will lock the standard output on each call. If you call +/// `println!` within a hot loop, this behavior may be the bottleneck of the loop. +/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]: +/// ``` +/// use std::io::{stdout, Write}; +/// +/// let mut lock = stdout().lock(); +/// writeln!(lock, "hello world").unwrap(); +/// ``` +/// +/// Use `println!` only for the primary output of your program. Use +/// [`eprintln!`] instead to print error and progress messages. +/// +/// See the formatting documentation in [`std::fmt`](crate::fmt) +/// for details of the macro argument syntax. +/// +/// [`std::fmt`]: crate::fmt +/// [`eprintln!`]: crate::eprintln +/// [lock]: crate::io::Stdout +/// +/// # Panics +/// +/// Panics if writing to [`io::stdout`] fails. +/// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// +/// [`io::stdout`]: crate::io::stdout +/// +/// # Examples +/// +/// ``` +/// println!(); // prints just a newline +/// println!("hello there!"); +/// println!("format {} arguments", "some"); +/// let local_variable = "some"; +/// println!("format {local_variable} arguments"); +/// ``` +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")] +#[allow_internal_unstable(print_internals, format_args_nl)] +macro_rules! println { + () => { + $crate::print!("\n") + }; + ($($arg:tt)*) => {{ + $crate::io::_print($crate::format_args_nl!($($arg)*)); + }}; +} + +/// Prints to the standard error. +/// +/// Equivalent to the [`print!`] macro, except that output goes to +/// [`io::stderr`] instead of [`io::stdout`]. See [`print!`] for +/// example usage. +/// +/// Use `eprint!` only for error and progress messages. Use `print!` +/// instead for the primary output of your program. +/// +/// [`io::stderr`]: crate::io::stderr +/// [`io::stdout`]: crate::io::stdout +/// +/// See the formatting documentation in [`std::fmt`](crate::fmt) +/// for details of the macro argument syntax. +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +/// +/// Writing to non-blocking stderr can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// eprint!("Error: Could not complete task"); +/// ``` +#[macro_export] +#[stable(feature = "eprint", since = "1.19.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")] +#[allow_internal_unstable(print_internals)] +macro_rules! eprint { + ($($arg:tt)*) => {{ + $crate::io::_eprint($crate::format_args!($($arg)*)); + }}; +} + +/// Prints to the standard error, with a newline. +/// +/// Equivalent to the [`println!`] macro, except that output goes to +/// [`io::stderr`] instead of [`io::stdout`]. See [`println!`] for +/// example usage. +/// +/// Use `eprintln!` only for error and progress messages. Use `println!` +/// instead for the primary output of your program. +/// +/// See the formatting documentation in [`std::fmt`](crate::fmt) +/// for details of the macro argument syntax. +/// +/// [`io::stderr`]: crate::io::stderr +/// [`io::stdout`]: crate::io::stdout +/// [`println!`]: crate::println +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +/// +/// Writing to non-blocking stderr can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// eprintln!("Error: Could not complete task"); +/// ``` +#[macro_export] +#[stable(feature = "eprint", since = "1.19.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")] +#[allow_internal_unstable(print_internals, format_args_nl)] +macro_rules! eprintln { + () => { + $crate::eprint!("\n") + }; + ($($arg:tt)*) => {{ + $crate::io::_eprint($crate::format_args_nl!($($arg)*)); + }}; +} + +/// Prints and returns the value of a given expression for quick and dirty +/// debugging. +/// +/// An example: +/// +/// ```rust +/// let a = 2; +/// let b = dbg!(a * 2) + 1; +/// // ^-- prints: [src/main.rs:2:9] a * 2 = 4 +/// assert_eq!(b, 5); +/// ``` +/// +/// The macro works by using the `Debug` implementation of the type of +/// the given expression to print the value to [stderr] along with the +/// source location of the macro invocation as well as the source code +/// of the expression. +/// +/// Invoking the macro on an expression moves and takes ownership of it +/// before returning the evaluated expression unchanged. If the type +/// of the expression does not implement `Copy` and you don't want +/// to give up ownership, you can instead borrow with `dbg!(&expr)` +/// for some expression `expr`. +/// +/// The `dbg!` macro works exactly the same in release builds. +/// This is useful when debugging issues that only occur in release +/// builds or when debugging in release mode is significantly faster. +/// +/// Note that the macro is intended as a debugging tool and therefore you +/// should avoid having uses of it in version control for long periods +/// (other than in tests and similar). +/// Debug output from production code is better done with other facilities +/// such as the [`debug!`] macro from the [`log`] crate. +/// +/// # Stability +/// +/// The exact output printed by this macro should not be relied upon +/// and is subject to future changes. +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +/// +/// # Further examples +/// +/// With a method call: +/// +/// ```rust +/// fn foo(n: usize) { +/// if let Some(_) = dbg!(n.checked_sub(4)) { +/// // ... +/// } +/// } +/// +/// foo(3) +/// ``` +/// +/// This prints to [stderr]: +/// +/// ```text,ignore +/// [src/main.rs:2:22] n.checked_sub(4) = None +/// ``` +/// +/// Naive factorial implementation: +/// +/// ```rust +/// fn factorial(n: u32) -> u32 { +/// if dbg!(n <= 1) { +/// dbg!(1) +/// } else { +/// dbg!(n * factorial(n - 1)) +/// } +/// } +/// +/// dbg!(factorial(4)); +/// ``` +/// +/// This prints to [stderr]: +/// +/// ```text,ignore +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = true +/// [src/main.rs:3:9] 1 = 1 +/// [src/main.rs:7:9] n * factorial(n - 1) = 2 +/// [src/main.rs:7:9] n * factorial(n - 1) = 6 +/// [src/main.rs:7:9] n * factorial(n - 1) = 24 +/// [src/main.rs:9:1] factorial(4) = 24 +/// ``` +/// +/// The `dbg!(..)` macro moves the input: +/// +/// ```compile_fail +/// /// A wrapper around `usize` which importantly is not Copyable. +/// #[derive(Debug)] +/// struct NoCopy(usize); +/// +/// let a = NoCopy(42); +/// let _ = dbg!(a); // <-- `a` is moved here. +/// let _ = dbg!(a); // <-- `a` is moved again; error! +/// ``` +/// +/// You can also use `dbg!()` without a value to just print the +/// file and line whenever it's reached. +/// +/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as +/// a tuple (and return it, too): +/// +/// ``` +/// assert_eq!(dbg!(1usize, 2u32), (1, 2)); +/// ``` +/// +/// However, a single argument with a trailing comma will still not be treated +/// as a tuple, following the convention of ignoring trailing commas in macro +/// invocations. You can use a 1-tuple directly if you need one: +/// +/// ``` +/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored +/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple +/// ``` +/// +/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr) +/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html +/// [`log`]: https://crates.io/crates/log +#[macro_export] +#[allow_internal_unstable(std_internals)] +#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")] +#[stable(feature = "dbg_macro", since = "1.32.0")] +macro_rules! dbg { + () => { + $crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!()) + }; + ($($val:expr),+ $(,)?) => { + $crate::macros::dbg_internal!(() () ($($val),+)) + }; +} + +/// Internal macro that processes a list of expressions and produces a chain of +/// nested `match`es, one for each expression, before finally calling `eprint!` +/// with the collected information and returning all the evaluated expressions +/// in a tuple. +/// +/// E.g. `dbg_internal!(() () (1, 2))` expands into +/// ```rust, ignore +/// match 1 { +/// tmp_1 => match 2 { +/// tmp_2 => { +/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); +/// (tmp_1, tmp_2) +/// } +/// } +/// } +/// ``` +/// +/// This is necessary so that `dbg!` outputs don't get torn, see #136703. +#[doc(hidden)] +#[rustc_macro_transparency = "semiopaque"] +pub macro dbg_internal { + (($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{ + $crate::eprint!( + $crate::concat!($($piece),+), + $( + $crate::stringify!($processed), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&$bound as &dyn $crate::fmt::Debug + ),+, + // The location returned here is that of the macro invocation, so + // it will be the same for all expressions. Thus, label these + // arguments so that they can be reused in every piece of the + // formatting template. + file=$crate::file!(), + line=$crate::line!(), + column=$crate::column!() + ); + // Comma separate the variables only when necessary so that this will + // not yield a tuple for a single expression, but rather just parenthesize + // the expression. + ($($bound),+) + }}, + (($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $val { + tmp => $crate::macros::dbg_internal!( + ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") + ($($processed => $bound,)* $val => tmp) + ($($rest),*) + ), + } + }, +} diff --git a/crates/std/src/pat.rs b/crates/std/src/pat.rs new file mode 100644 index 0000000..aeddd84 --- /dev/null +++ b/crates/std/src/pat.rs @@ -0,0 +1,3 @@ +//! Helper module for exporting the `pattern_type` macro + +pub use core::pattern_type; diff --git a/crates/std/src/path.rs b/crates/std/src/path.rs index 04112b5..1c375cc 100644 --- a/crates/std/src/path.rs +++ b/crates/std/src/path.rs @@ -92,8 +92,8 @@ use crate::iter::FusedIterator; use crate::ops::{self, Deref}; use crate::rc::Rc; use crate::str::FromStr; -use alloc_crate::sync::Arc; -use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; +use crate::sync::Arc; +use crate::sys::path::{HAS_PREFIXES, is_sep_byte, is_verbatim_sep, parse_prefix}; use crate::{cmp, fmt, fs, io, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -266,22 +266,33 @@ impl<'a> Prefix<'a> { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub fn is_separator(c: char) -> bool { +#[rustc_const_unstable(feature = "const_path_separators", issue = "153106")] +pub const fn is_separator(c: char) -> bool { c.is_ascii() && is_sep_byte(c as u8) } -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. +/// All path separators recognized on the current platform, represented as [`char`]s; for example, +/// this is `&['/'][..]` on Unix and `&['\\', '/'][..]` on Windows. The [primary +/// separator](MAIN_SEPARATOR) is always element 0 of the slice. +#[unstable(feature = "const_path_separators", issue = "153106")] +pub const SEPARATORS: &[char] = crate::sys::path::SEPARATORS; + +/// All path separators recognized on the current platform, represented as [`&str`]s; for example, +/// this is `&["/"][..]` on Unix and `&["\\", "/"][..]` on Windows. The [primary +/// separator](MAIN_SEPARATOR_STR) is always element 0 of the slice. +#[unstable(feature = "const_path_separators", issue = "153106")] +pub const SEPARATORS_STR: &[&str] = crate::sys::path::SEPARATORS_STR; + +/// The primary separator of path components for the current platform, represented as a [`char`]; +/// for example, this is `'/'` on Unix and `'\\'` on Windows. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "path_main_separator")] -pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP; +pub const MAIN_SEPARATOR: char = SEPARATORS[0]; -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. +/// The primary separator of path components for the current platform, represented as a [`&str`]; +/// for example, this is `"/"` on Unix and `"\\"` on Windows. #[stable(feature = "main_separator_str", since = "1.68.0")] -pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR; +pub const MAIN_SEPARATOR_STR: &str = SEPARATORS_STR[0]; //////////////////////////////////////////////////////////////////////////////// // Misc helpers @@ -562,7 +573,7 @@ impl<'a> Component<'a> { pub fn as_os_str(self) -> &'a OsStr { match self { Component::Prefix(p) => p.as_os_str(), - Component::RootDir => OsStr::new(MAIN_SEP_STR), + Component::RootDir => OsStr::new(MAIN_SEPARATOR_STR), Component::CurDir => OsStr::new("."), Component::ParentDir => OsStr::new(".."), Component::Normal(path) => path, @@ -1379,7 +1390,7 @@ impl PathBuf { for c in buf { if need_sep && c != Component::RootDir { - res.push(MAIN_SEP_STR); + res.push(MAIN_SEPARATOR_STR); } res.push(c.as_os_str()); @@ -1402,7 +1413,7 @@ impl PathBuf { // `path` is a pure relative path } else if need_sep { - self.inner.push(MAIN_SEP_STR); + self.inner.push(MAIN_SEPARATOR_STR); } self.inner.push(path); @@ -3240,73 +3251,101 @@ impl Path { self } - // /// Queries the file system to get information about a file, directory, etc. - // /// - // /// This function will traverse symbolic links to query information about the - // /// destination file. - // /// - // /// This is an alias to [`fs::metadata`]. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// - // /// let path = Path::new("/Minas/tirith"); - // /// let metadata = path.metadata().expect("metadata call failed"); - // /// println!("{:?}", metadata.file_type()); - // /// ``` - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[inline] - // pub fn metadata(&self) -> io::Result { - // fs::metadata(self) - // } + /// Queries the file system to get information about a file, directory, etc. + /// + /// This function will traverse symbolic links to query information about the + /// destination file. + /// + /// This is an alias to [`fs::metadata`]. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/Minas/tirith"); + /// let metadata = path.metadata().expect("metadata call failed"); + /// println!("{:?}", metadata.file_type()); + /// ``` + #[stable(feature = "path_ext", since = "1.5.0")] + #[inline] + pub fn metadata(&self) -> io::Result { + fs::metadata(self) + } - // /// Queries the metadata about a file without following symlinks. - // /// - // /// This is an alias to [`fs::symlink_metadata`]. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// - // /// let path = Path::new("/Minas/tirith"); - // /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed"); - // /// println!("{:?}", metadata.file_type()); - // /// ``` - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[inline] - // pub fn symlink_metadata(&self) -> io::Result { - // fs::symlink_metadata(self) - // } + /// Queries the metadata about a file without following symlinks. + /// + /// This is an alias to [`fs::symlink_metadata`]. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/Minas/tirith"); + /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed"); + /// println!("{:?}", metadata.file_type()); + /// ``` + #[stable(feature = "path_ext", since = "1.5.0")] + #[inline] + pub fn symlink_metadata(&self) -> io::Result { + fs::symlink_metadata(self) + } - // /// Returns the canonical, absolute form of the path with all intermediate - // /// components normalized and symbolic links resolved. - // /// - // /// This is an alias to [`fs::canonicalize`]. - // /// - // /// # Errors - // /// - // /// This method will return an error in the following situations, but is not - // /// limited to just these cases: - // /// - // /// * `path` does not exist. - // /// * A non-final component in path is not a directory. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::{Path, PathBuf}; - // /// - // /// let path = Path::new("/foo/test/../test/bar.rs"); - // /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); - // /// ``` - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[inline] - // pub fn canonicalize(&self) -> io::Result { - // fs::canonicalize(self) - // } + /// Returns the canonical, absolute form of the path with all intermediate + /// components normalized and symbolic links resolved. + /// + /// This is an alias to [`fs::canonicalize`]. + /// + /// # Errors + /// + /// This method will return an error in the following situations, but is not + /// limited to just these cases: + /// + /// * `path` does not exist. + /// * A non-final component in path is not a directory. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("/foo/test/../test/bar.rs"); + /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); + /// ``` + #[stable(feature = "path_ext", since = "1.5.0")] + #[inline] + pub fn canonicalize(&self) -> io::Result { + fs::canonicalize(self) + } + + /// Makes the path absolute without accessing the filesystem. + /// + /// This is an alias to [`path::absolute`](absolute). + /// + /// # Errors + /// + /// This function may return an error in the following situations: + /// + /// * If the path is syntactically invalid; in particular, if it is empty. + /// * If getting the [current directory][crate::env::current_dir] fails. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(path_absolute_method)] + /// use std::path::Path; + /// + /// let path = Path::new("foo/./bar"); + /// let absolute = path.absolute()?; + /// assert!(absolute.is_absolute()); + /// # Ok::<(), std::io::Error>(()) + /// ``` + #[unstable(feature = "path_absolute_method", issue = "153328")] + #[inline] + pub fn absolute(&self) -> io::Result { + absolute(self) + } /// Normalize a path, including `..` without traversing the filesystem. /// @@ -3369,206 +3408,206 @@ impl Path { Ok(lexical) } - // /// Reads a symbolic link, returning the file that the link points to. - // /// - // /// This is an alias to [`fs::read_link`]. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// - // /// let path = Path::new("/laputa/sky_castle.rs"); - // /// let path_link = path.read_link().expect("read_link call failed"); - // /// ``` - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[inline] - // pub fn read_link(&self) -> io::Result { - // fs::read_link(self) - // } + /// Reads a symbolic link, returning the file that the link points to. + /// + /// This is an alias to [`fs::read_link`]. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/laputa/sky_castle.rs"); + /// let path_link = path.read_link().expect("read_link call failed"); + /// ``` + #[stable(feature = "path_ext", since = "1.5.0")] + #[inline] + pub fn read_link(&self) -> io::Result { + fs::read_link(self) + } - // /// Returns an iterator over the entries within a directory. - // /// - // /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New - // /// errors may be encountered after an iterator is initially constructed. - // /// - // /// This is an alias to [`fs::read_dir`]. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// - // /// let path = Path::new("/laputa"); - // /// for entry in path.read_dir().expect("read_dir call failed") { - // /// if let Ok(entry) = entry { - // /// println!("{:?}", entry.path()); - // /// } - // /// } - // /// ``` - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[inline] - // pub fn read_dir(&self) -> io::Result { - // fs::read_dir(self) - // } + /// Returns an iterator over the entries within a directory. + /// + /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New + /// errors may be encountered after an iterator is initially constructed. + /// + /// This is an alias to [`fs::read_dir`]. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/laputa"); + /// for entry in path.read_dir().expect("read_dir call failed") { + /// if let Ok(entry) = entry { + /// println!("{:?}", entry.path()); + /// } + /// } + /// ``` + #[stable(feature = "path_ext", since = "1.5.0")] + #[inline] + pub fn read_dir(&self) -> io::Result { + fs::read_dir(self) + } - // /// Returns `true` if the path points at an existing entity. - // /// - // /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! - // /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs. - // /// - // /// This function will traverse symbolic links to query information about the - // /// destination file. - // /// - // /// If you cannot access the metadata of the file, e.g. because of a - // /// permission error or broken symbolic links, this will return `false`. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// assert!(!Path::new("does_not_exist.txt").exists()); - // /// ``` - // /// - // /// # See Also - // /// - // /// This is a convenience function that coerces errors to false. If you want to - // /// check errors, call [`Path::try_exists`]. - // /// - // /// [`try_exists()`]: Self::try_exists - // /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[must_use] - // #[inline] - // pub fn exists(&self) -> bool { - // fs::metadata(self).is_ok() - // } + /// Returns `true` if the path points at an existing entity. + /// + /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! + /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs. + /// + /// This function will traverse symbolic links to query information about the + /// destination file. + /// + /// If you cannot access the metadata of the file, e.g. because of a + /// permission error or broken symbolic links, this will return `false`. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// assert!(!Path::new("does_not_exist.txt").exists()); + /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [`Path::try_exists`]. + /// + /// [`try_exists()`]: Self::try_exists + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou + #[stable(feature = "path_ext", since = "1.5.0")] + #[must_use] + #[inline] + pub fn exists(&self) -> bool { + fs::metadata(self).is_ok() + } - // /// Returns `Ok(true)` if the path points at an existing entity. - // /// - // /// This function will traverse symbolic links to query information about the - // /// destination file. In case of broken symbolic links this will return `Ok(false)`. - // /// - // /// [`Path::exists()`] only checks whether or not a path was both found and readable. By - // /// contrast, `try_exists` will return `Ok(true)` or `Ok(false)`, respectively, if the path - // /// was _verified_ to exist or not exist. If its existence can neither be confirmed nor - // /// denied, it will propagate an `Err(_)` instead. This can be the case if e.g. listing - // /// permission is denied on one of the parent directories. - // /// - // /// Note that while this avoids some pitfalls of the `exists()` method, it still can not - // /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios - // /// where those bugs are not an issue. - // /// - // /// This is an alias for [`std::fs::exists`](crate::fs::exists). - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt")); - // /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err()); - // /// ``` - // /// - // /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou - // /// [`exists()`]: Self::exists - // #[stable(feature = "path_try_exists", since = "1.63.0")] - // #[inline] - // pub fn try_exists(&self) -> io::Result { - // fs::exists(self) - // } + /// Returns `Ok(true)` if the path points at an existing entity. + /// + /// This function will traverse symbolic links to query information about the + /// destination file. In case of broken symbolic links this will return `Ok(false)`. + /// + /// [`Path::exists()`] only checks whether or not a path was both found and readable. By + /// contrast, `try_exists` will return `Ok(true)` or `Ok(false)`, respectively, if the path + /// was _verified_ to exist or not exist. If its existence can neither be confirmed nor + /// denied, it will propagate an `Err(_)` instead. This can be the case if e.g. listing + /// permission is denied on one of the parent directories. + /// + /// Note that while this avoids some pitfalls of the `exists()` method, it still can not + /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios + /// where those bugs are not an issue. + /// + /// This is an alias for [`std::fs::exists`](crate::fs::exists). + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt")); + /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err()); + /// ``` + /// + /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou + /// [`exists()`]: Self::exists + #[stable(feature = "path_try_exists", since = "1.63.0")] + #[inline] + pub fn try_exists(&self) -> io::Result { + fs::exists(self) + } - // /// Returns `true` if the path exists on disk and is pointing at a regular file. - // /// - // /// This function will traverse symbolic links to query information about the - // /// destination file. - // /// - // /// If you cannot access the metadata of the file, e.g. because of a - // /// permission error or broken symbolic links, this will return `false`. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); - // /// assert_eq!(Path::new("a_file.txt").is_file(), true); - // /// ``` - // /// - // /// # See Also - // /// - // /// This is a convenience function that coerces errors to false. If you want to - // /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call - // /// [`fs::Metadata::is_file`] if it was [`Ok`]. - // /// - // /// When the goal is simply to read from (or write to) the source, the most - // /// reliable way to test the source can be read (or written to) is to open - // /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on - // /// a Unix-like system for example. See [`fs::File::open`] or - // /// [`fs::OpenOptions::open`] for more information. - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[must_use] - // pub fn is_file(&self) -> bool { - // fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) - // } + /// Returns `true` if the path exists on disk and is pointing at a regular file. + /// + /// This function will traverse symbolic links to query information about the + /// destination file. + /// + /// If you cannot access the metadata of the file, e.g. because of a + /// permission error or broken symbolic links, this will return `false`. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); + /// assert_eq!(Path::new("a_file.txt").is_file(), true); + /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call + /// [`fs::Metadata::is_file`] if it was [`Ok`]. + /// + /// When the goal is simply to read from (or write to) the source, the most + /// reliable way to test the source can be read (or written to) is to open + /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on + /// a Unix-like system for example. See [`fs::File::open`] or + /// [`fs::OpenOptions::open`] for more information. + #[stable(feature = "path_ext", since = "1.5.0")] + #[must_use] + pub fn is_file(&self) -> bool { + fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) + } - // /// Returns `true` if the path exists on disk and is pointing at a directory. - // /// - // /// This function will traverse symbolic links to query information about the - // /// destination file. - // /// - // /// If you cannot access the metadata of the file, e.g. because of a - // /// permission error or broken symbolic links, this will return `false`. - // /// - // /// # Examples - // /// - // /// ```no_run - // /// use std::path::Path; - // /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); - // /// assert_eq!(Path::new("a_file.txt").is_dir(), false); - // /// ``` - // /// - // /// # See Also - // /// - // /// This is a convenience function that coerces errors to false. If you want to - // /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call - // /// [`fs::Metadata::is_dir`] if it was [`Ok`]. - // #[stable(feature = "path_ext", since = "1.5.0")] - // #[must_use] - // pub fn is_dir(&self) -> bool { - // fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) - // } + /// Returns `true` if the path exists on disk and is pointing at a directory. + /// + /// This function will traverse symbolic links to query information about the + /// destination file. + /// + /// If you cannot access the metadata of the file, e.g. because of a + /// permission error or broken symbolic links, this will return `false`. + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); + /// assert_eq!(Path::new("a_file.txt").is_dir(), false); + /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call + /// [`fs::Metadata::is_dir`] if it was [`Ok`]. + #[stable(feature = "path_ext", since = "1.5.0")] + #[must_use] + pub fn is_dir(&self) -> bool { + fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) + } - // /// Returns `true` if the path exists on disk and is pointing at a symbolic link. - // /// - // /// This function will not traverse symbolic links. - // /// In case of a broken symbolic link this will also return true. - // /// - // /// If you cannot access the directory containing the file, e.g., because of a - // /// permission error, this will return false. - // /// - // /// # Examples - // /// - // /// ```rust,no_run - // /// # #[cfg(unix)] { - // /// use std::path::Path; - // /// use std::os::unix::fs::symlink; - // /// - // /// let link_path = Path::new("link"); - // /// symlink("/origin_does_not_exist/", link_path).unwrap(); - // /// assert_eq!(link_path.is_symlink(), true); - // /// assert_eq!(link_path.exists(), false); - // /// # } - // /// ``` - // /// - // /// # See Also - // /// - // /// This is a convenience function that coerces errors to false. If you want to - // /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call - // /// [`fs::Metadata::is_symlink`] if it was [`Ok`]. - // #[must_use] - // #[stable(feature = "is_symlink", since = "1.58.0")] - // pub fn is_symlink(&self) -> bool { - // fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false) - // } + /// Returns `true` if the path exists on disk and is pointing at a symbolic link. + /// + /// This function will not traverse symbolic links. + /// In case of a broken symbolic link this will also return true. + /// + /// If you cannot access the directory containing the file, e.g., because of a + /// permission error, this will return false. + /// + /// # Examples + /// + /// ```rust,no_run + /// # #[cfg(unix)] { + /// use std::path::Path; + /// use std::os::unix::fs::symlink; + /// + /// let link_path = Path::new("link"); + /// symlink("/origin_does_not_exist/", link_path).unwrap(); + /// assert_eq!(link_path.is_symlink(), true); + /// assert_eq!(link_path.exists(), false); + /// # } + /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call + /// [`fs::Metadata::is_symlink`] if it was [`Ok`]. + #[must_use] + #[stable(feature = "is_symlink", since = "1.58.0")] + pub fn is_symlink(&self) -> bool { + fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false) + } /// Converts a [`Box`](Box) into a [`PathBuf`] without copying or /// allocating. diff --git a/crates/std/src/prelude.rs b/crates/std/src/prelude.rs index 79e0617..1074d12 100644 --- a/crates/std/src/prelude.rs +++ b/crates/std/src/prelude.rs @@ -17,6 +17,10 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::vec::Vec; + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use crate::option::Option::{self, None, Some}; + // Re-exported built-in macros and traits #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[doc(no_inline)] @@ -150,12 +154,6 @@ pub mod rust_2024 { } } - // #[panic_handler] - // fn panic(_panic_info: &core::panic::PanicInfo) -> ! { - // // TODO print - // loop {} - // } - /// # Safety /// `argc` and `argv` are passed by the kernel #[unsafe(no_mangle)] @@ -166,16 +164,4 @@ pub mod rust_2024 { unsafe { main(argc, argv) } } - - #[lang = "start"] - pub fn lang_start( - main: fn() -> T, - argc: isize, - argv: *const *const u8, - _sigpipe: u8, - ) -> isize { - println!("{}", argc); - println!("{:?}", argv); - main().report().to_i32() as isize - } } diff --git a/crates/std/src/process.rs b/crates/std/src/process.rs index 0d7e5d1..321b68b 100644 --- a/crates/std/src/process.rs +++ b/crates/std/src/process.rs @@ -156,6 +156,7 @@ target_env = "sgx", target_os = "xous", target_os = "trusty", + target_os = "hermit", )) ))] mod tests; @@ -1380,6 +1381,7 @@ impl Output { /// # Examples /// /// ``` + /// # #![allow(unused_features)] /// #![feature(exit_status_error)] /// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] { /// use std::process::Command; @@ -1679,32 +1681,32 @@ impl From for Stdio { } } -// #[stable(feature = "stdio_from", since = "1.20.0")] -// impl From for Stdio { -// /// Converts a [`File`](fs::File) into a [`Stdio`]. -// /// -// /// # Examples -// /// -// /// `File` will be converted to `Stdio` using `Stdio::from` under the hood. -// /// -// /// ```rust,no_run -// /// use std::fs::File; -// /// use std::process::Command; -// /// -// /// // With the `foo.txt` file containing "Hello, world!" -// /// let file = File::open("foo.txt")?; -// /// -// /// let reverse = Command::new("rev") -// /// .stdin(file) // Implicit File conversion into a Stdio -// /// .output()?; -// /// -// /// assert_eq!(reverse.stdout, b"!dlrow ,olleH"); -// /// # std::io::Result::Ok(()) -// /// ``` -// fn from(file: fs::File) -> Stdio { -// Stdio::from_inner(file.into_inner().into()) -// } -// } +#[stable(feature = "stdio_from", since = "1.20.0")] +impl From for Stdio { + /// Converts a [`File`](fs::File) into a [`Stdio`]. + /// + /// # Examples + /// + /// `File` will be converted to `Stdio` using `Stdio::from` under the hood. + /// + /// ```rust,no_run + /// use std::fs::File; + /// use std::process::Command; + /// + /// // With the `foo.txt` file containing "Hello, world!" + /// let file = File::open("foo.txt")?; + /// + /// let reverse = Command::new("rev") + /// .stdin(file) // Implicit File conversion into a Stdio + /// .output()?; + /// + /// assert_eq!(reverse.stdout, b"!dlrow ,olleH"); + /// # std::io::Result::Ok(()) + /// ``` + fn from(file: fs::File) -> Stdio { + Stdio::from_inner(file.into_inner().into()) + } +} #[stable(feature = "stdio_from_stdio", since = "1.74.0")] impl From for Stdio { @@ -1959,6 +1961,7 @@ impl crate::sealed::Sealed for ExitStatusError {} pub struct ExitStatusError(imp::ExitStatusError); #[unstable(feature = "exit_status_error", issue = "84908")] +#[doc(test(attr(allow(unused_features))))] impl ExitStatusError { /// Reports the exit code, if applicable, from an `ExitStatusError`. /// @@ -2545,7 +2548,7 @@ pub fn abort() -> ! { #[must_use] #[stable(feature = "getpid", since = "1.26.0")] pub fn id() -> u32 { - todo!() + imp::getpid() } /// A trait for implementing arbitrary return types in the `main` function. diff --git a/crates/std/src/random.rs b/crates/std/src/random.rs new file mode 100644 index 0000000..a18dcf9 --- /dev/null +++ b/crates/std/src/random.rs @@ -0,0 +1,96 @@ +//! Random value generation. + +#[unstable(feature = "random", issue = "130703")] +pub use core::random::*; + +use crate::sys::random as sys; + +/// The default random source. +/// +/// This asks the system for random data suitable for cryptographic purposes +/// such as key generation. If security is a concern, consult the platform +/// documentation below for the specific guarantees your target provides. +/// +/// The high quality of randomness provided by this source means it can be quite +/// slow on some targets. If you need a large quantity of random numbers and +/// security is not a concern, consider using an alternative random number +/// generator (potentially seeded from this one). +/// +/// # Underlying sources +/// +/// Platform | Source +/// -----------------------|--------------------------------------------------------------- +/// Linux | [`getrandom`] or [`/dev/urandom`] after polling `/dev/random` +/// Windows | [`ProcessPrng`](https://learn.microsoft.com/en-us/windows/win32/seccng/processprng) +/// Apple | `CCRandomGenerateBytes` +/// DragonFly | [`arc4random_buf`](https://man.dragonflybsd.org/?command=arc4random) +/// ESP-IDF | [`esp_fill_random`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t) +/// FreeBSD | [`arc4random_buf`](https://man.freebsd.org/cgi/man.cgi?query=arc4random) +/// Fuchsia | [`cprng_draw`](https://fuchsia.dev/reference/syscalls/cprng_draw) +/// Haiku | `arc4random_buf` +/// Illumos | [`arc4random_buf`](https://www.illumos.org/man/3C/arc4random) +/// NetBSD | [`arc4random_buf`](https://man.netbsd.org/arc4random.3) +/// OpenBSD | [`arc4random_buf`](https://man.openbsd.org/arc4random.3) +/// Solaris | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html) +/// Vita | `arc4random_buf` +/// Hermit | `read_entropy` +/// Horizon, Cygwin | `getrandom` +/// AIX, Hurd, L4Re, QNX | `/dev/urandom` +/// Redox | `/scheme/rand` +/// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/main/bsp-howto/getentropy.html) +/// SGX | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND) +/// SOLID | `SOLID_RNG_SampleRandomBytes` +/// TEEOS | `TEE_GenerateRandom` +/// UEFI | [`EFI_RNG_PROTOCOL`](https://uefi.org/specs/UEFI/2.10/37_Secure_Technologies.html#random-number-generator-protocol) +/// VxWorks | `randABytes` after waiting for `randSecure` to become ready +/// WASI | [`random_get`](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-random_getbuf-pointeru8-buf_len-size---result-errno) +/// ZKVM | `sys_rand` +/// +/// Note that the sources used might change over time. +/// +/// Consult the documentation for the underlying operations on your supported +/// targets to determine whether they provide any particular desired properties, +/// such as support for reseeding on VM fork operations. +/// +/// [`getrandom`]: https://www.man7.org/linux/man-pages/man2/getrandom.2.html +/// [`/dev/urandom`]: https://www.man7.org/linux/man-pages/man4/random.4.html +#[derive(Default, Debug, Clone, Copy)] +#[unstable(feature = "random", issue = "130703")] +pub struct DefaultRandomSource; + +#[unstable(feature = "random", issue = "130703")] +impl RandomSource for DefaultRandomSource { + fn fill_bytes(&mut self, bytes: &mut [u8]) { + sys::fill_bytes(bytes) + } +} + +/// Generates a random value from a distribution, using the default random source. +/// +/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and will sample +/// according to the same distribution as the underlying [`Distribution`] trait implementation. See +/// [`DefaultRandomSource`] for more information about how randomness is sourced. +/// +/// # Examples +/// +/// Generating a [version 4/variant 1 UUID] represented as text: +/// ``` +/// #![feature(random)] +/// +/// use std::random::random; +/// +/// let bits: u128 = random(..); +/// let g1 = (bits >> 96) as u32; +/// let g2 = (bits >> 80) as u16; +/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16; +/// let g4 = (0x8000 | (bits >> 48) & 0x3fff) as u16; +/// let g5 = (bits & 0xffffffffffff) as u64; +/// let uuid = format!("{g1:08x}-{g2:04x}-{g3:04x}-{g4:04x}-{g5:012x}"); +/// println!("{uuid}"); +/// ``` +/// +/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) +#[unstable(feature = "random", issue = "130703")] +pub fn random(dist: impl Distribution) -> T { + dist.sample(&mut DefaultRandomSource) +} diff --git a/crates/std/src/rt.rs b/crates/std/src/rt.rs index a57534c..1e7de69 100644 --- a/crates/std/src/rt.rs +++ b/crates/std/src/rt.rs @@ -1,8 +1,211 @@ -macro_rules! rtabort { - ($($t:tt)*) => {{ loop {} }}; -} -macro_rules! rtprintpanic { - ($($t:tt)*) => {{}}; +//! Runtime services +//! +//! The `rt` module provides a narrow set of runtime services, +//! including the global heap (exported in `heap`) and unwinding and +//! backtrace support. The APIs in this module are highly unstable, +//! and should be considered as private implementation details for the +//! time being. + +#![unstable( + feature = "rt", + reason = "this public module should not exist and is highly likely \ + to disappear", + issue = "none" +)] +#![doc(hidden)] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(unused_macros)] + +#[rustfmt::skip] +pub use crate::panicking::{begin_panic, panic_count}; +pub use core::panicking::{panic_display, panic_fmt}; + +#[rustfmt::skip] +use crate::any::Any; +use crate::sync::Once; +use crate::thread::{self, main_thread}; +use crate::{mem, panic, sys}; + +// This function is needed by the panic runtime. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +fn __rust_abort() { + crate::process::abort(); } -pub fn cleanup() {} +// Prints to the "panic output", depending on the platform this may be: +// - the standard error output +// - some dedicated platform specific output +// - nothing (so this macro is a no-op) +macro_rules! rtprintpanic { + ($($t:tt)*) => { + #[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(panic = "immediate-abort")] + { + let _ = format_args!($($t)*); + } + } +} + +macro_rules! rtabort { + ($($t:tt)*) => { + { + rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*)); + crate::process::abort(); + } + } +} + +macro_rules! rtassert { + ($e:expr) => { + if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + } + }; +} + +macro_rules! rtunwrap { + ($ok:ident, $e:expr) => { + match $e { + $ok(v) => v, + ref err => { + let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug + rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) + } + } + }; +} + +fn handle_rt_panic(e: Box) -> T { + mem::forget(e); + rtabort!("initialization or cleanup bug"); +} + +// One-time runtime initialization. +// Runs before `main`. +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +// +// # The `sigpipe` parameter +// +// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to +// `SIG_IGN`. Applications have good reasons to want a different behavior +// though, so there is a `-Zon-broken-pipe` compiler flag that +// can be used to select how `SIGPIPE` shall be setup (if changed at all) before +// `fn main()` is called. See +// for more info. +// +// The `sigpipe` parameter to this function gets its value via the code that +// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for +// all platforms and not only Unix, is because std is not allowed to have `cfg` +// directives as this high level. See the module docs in +// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe` +// has a value, but its value is ignored. +// +// Even though it is an `u8`, it only ever has 4 values. These are documented in +// `compiler/rustc_session/src/config/sigpipe.rs`. +#[cfg_attr(test, allow(dead_code))] +unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { + // Remember the main thread ID to give it the correct name. + // SAFETY: this is the only time and place where we call this function. + unsafe { main_thread::set(thread::current_id()) }; + + #[cfg_attr(target_os = "teeos", allow(unused_unsafe))] + unsafe { + sys::init(argc, argv, sigpipe) + }; +} + +/// Clean up the thread-local runtime state. This *should* be run after all other +/// code managed by the Rust runtime, but will not cause UB if that condition is +/// not fulfilled. Also note that this function is not guaranteed to be run, but +/// skipping it will cause leaks and therefore is to be avoided. +pub(crate) fn thread_cleanup() { + // This function is run in situations where unwinding leads to an abort + // (think `extern "C"` functions). Abort here instead so that we can + // print a nice message. + panic::catch_unwind(|| { + crate::thread::drop_current(); + }) + .unwrap_or_else(handle_rt_panic); +} + +// One-time runtime cleanup. +// Runs after `main` or at program exit. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub(crate) fn cleanup() { + static CLEANUP: Once = Once::new(); + CLEANUP.call_once(|| unsafe { + // Flush stdout and disable buffering. + crate::io::cleanup(); + // SAFETY: Only called once during runtime cleanup. + sys::cleanup(); + }); +} + +// To reduce the generated code of the new `lang_start`, this function is doing +// the real work. +#[cfg(not(test))] +fn lang_start_internal( + main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), + argc: isize, + argv: *const *const u8, + sigpipe: u8, +) -> isize { + // Guard against the code called by this function from unwinding outside of the Rust-controlled + // code, which is UB. This is a requirement imposed by a combination of how the + // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking + // 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 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. + // + // We use `catch_unwind` with `handle_rt_panic` instead of `abort_unwind` to make the error in + // case of a panic a bit nicer. + panic::catch_unwind(move || { + // SAFETY: Only called once during runtime initialization. + unsafe { init(argc, argv, sigpipe) }; + + let ret_code = panic::catch_unwind(main).unwrap_or_else(move |payload| { + // Carefully dispose of the panic payload. + let payload = panic::AssertUnwindSafe(payload); + panic::catch_unwind(move || drop({ payload }.0)).unwrap_or_else(move |e| { + mem::forget(e); // do *not* drop the 2nd payload + rtabort!("drop of the panic payload panicked"); + }); + // Return error code for panicking programs. + 101 + }); + let ret_code = ret_code as isize; + + cleanup(); + // Guard against multiple threads calling `libc::exit` concurrently. + // See the documentation for `unique_thread_exit` for more information. + crate::sys::exit::unique_thread_exit(); + + ret_code + }) + .unwrap_or_else(handle_rt_panic) +} + +#[cfg(not(any(test, doctest)))] +#[lang = "start"] +fn lang_start( + main: fn() -> T, + argc: isize, + argv: *const *const u8, + sigpipe: u8, +) -> isize { + lang_start_internal( + &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), + argc, + argv, + sigpipe, + ) +} diff --git a/crates/std/src/sync.rs b/crates/std/src/sync.rs index b494a67..b76500d 100644 --- a/crates/std/src/sync.rs +++ b/crates/std/src/sync.rs @@ -14,18 +14,19 @@ pub use core::sync::atomic; pub use once::Once; pub use once::OnceState; +pub use alloc_crate::sync::Arc; +pub use lazy_lock::LazyLock; +pub use once_lock::OnceLock; +pub use poison::Condvar; pub use poison::LockResult; pub use poison::Mutex; pub use poison::MutexGuard; pub use poison::PoisonError; +pub use poison::RwLock; pub use poison::TryLockError; pub use poison::TryLockResult; -pub use poison::Condvar; -pub use poison::RwLock; -pub use once_lock::OnceLock; pub use reentrant_lock::ReentrantLock; pub use reentrant_lock::ReentrantLockGuard; -pub use alloc_crate::sync::Arc; #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[stable(feature = "wait_timeout", since = "1.5.0")] diff --git a/crates/std/src/sync/lazy_lock.rs b/crates/std/src/sync/lazy_lock.rs index 7274b5d..9bdde0a 100644 --- a/crates/std/src/sync/lazy_lock.rs +++ b/crates/std/src/sync/lazy_lock.rs @@ -105,15 +105,6 @@ impl T> LazyLock { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } - /// Creates a new lazy value that is already initialized. - #[inline] - #[cfg(test)] - pub(crate) fn preinit(value: T) -> LazyLock { - let once = Once::new(); - once.call_once(|| {}); - LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } - } - /// Consumes this `LazyLock` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. @@ -404,6 +395,19 @@ impl fmt::Debug for LazyLock { } } +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for LazyLock { + /// Constructs a `LazyLock` that starts already initialized + /// with the provided value. + #[inline] + fn from(value: T) -> Self { + LazyLock { + once: Once::new_complete(), + data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }), + } + } +} + #[cold] #[inline(never)] fn panic_poisoned() -> ! { diff --git a/crates/std/src/sync/mpmc/context.rs b/crates/std/src/sync/mpmc/context.rs index 941575f..6b2f4cb 100644 --- a/crates/std/src/sync/mpmc/context.rs +++ b/crates/std/src/sync/mpmc/context.rs @@ -4,7 +4,7 @@ use super::select::Selected; use super::waker::current_thread_id; use crate::cell::Cell; use crate::ptr; -use alloc_crate::sync::Arc; +use crate::sync::Arc; use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize, Ordering}; use crate::thread::{self, Thread}; use crate::time::Instant; diff --git a/crates/std/src/sync/once.rs b/crates/std/src/sync/once.rs index bcfc9f5..2556d18 100644 --- a/crates/std/src/sync/once.rs +++ b/crates/std/src/sync/once.rs @@ -84,6 +84,13 @@ impl Once { Once { inner: sys::Once::new() } } + /// Creates a new `Once` value that starts already completed. + #[inline] + #[must_use] + pub(crate) const fn new_complete() -> Once { + Once { inner: sys::Once::new_complete() } + } + /// Performs an initialization routine once and only once. The given closure /// will be executed if this is the first time `call_once` has been called, /// and otherwise the routine will *not* be invoked. diff --git a/crates/std/src/sys/helpers/mod.rs b/crates/std/src/sys/helpers/mod.rs new file mode 100644 index 0000000..a623679 --- /dev/null +++ b/crates/std/src/sys/helpers/mod.rs @@ -0,0 +1,39 @@ +//! Small helper functions used inside `sys`. +//! +//! If any of these have uses outside of `sys`, please move them to a different +//! module. + +#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. +mod small_c_string; +#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. +mod wstr; + +#[cfg(test)] +mod tests; + +#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. +pub use small_c_string::{run_path_with_cstr, run_with_cstr}; +#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. +pub use wstr::WStrUnits; + +/// Computes `(value*numerator)/denom` without overflow, as long as both +/// `numerator*denom` and the overall result fit into `u64` (which is the case +/// for our time conversions). +#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. +pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 { + let q = value / denom; + let r = value % denom; + // Decompose value as (value/denom*denom + value%denom), + // substitute into (value*numerator)/denom and simplify. + // r < denom, so (denom*numerator) is the upper bound of (r*numerator) + q * numerator + r * numerator / denom +} + +#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. +pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> { + match result { + Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()), + Ok(_) => Ok(()), + Err(err) => Err(err), + } +} diff --git a/crates/std/src/sys/helpers/small_c_string.rs b/crates/std/src/sys/helpers/small_c_string.rs new file mode 100644 index 0000000..f54505a --- /dev/null +++ b/crates/std/src/sys/helpers/small_c_string.rs @@ -0,0 +1,60 @@ +use crate::ffi::{CStr, CString}; +use crate::mem::MaybeUninit; +use crate::path::Path; +use crate::{io, ptr, slice}; + +// Make sure to stay under 4096 so the compiler doesn't insert a probe frame: +// https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html +#[cfg(not(target_os = "espidf"))] +const MAX_STACK_ALLOCATION: usize = 384; +#[cfg(target_os = "espidf")] +const MAX_STACK_ALLOCATION: usize = 32; + +const NUL_ERR: io::Error = + io::const_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte"); + +#[inline] +pub fn run_path_with_cstr(path: &Path, f: &dyn Fn(&CStr) -> io::Result) -> io::Result { + run_with_cstr(path.as_os_str().as_encoded_bytes(), f) +} + +#[inline] +pub fn run_with_cstr(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result) -> io::Result { + // Dispatch and dyn erase the closure type to prevent mono bloat. + // See https://github.com/rust-lang/rust/pull/121101. + if bytes.len() >= MAX_STACK_ALLOCATION { + run_with_cstr_allocating(bytes, f) + } else { + unsafe { run_with_cstr_stack(bytes, f) } + } +} + +/// # Safety +/// +/// `bytes` must have a length less than `MAX_STACK_ALLOCATION`. +unsafe fn run_with_cstr_stack( + bytes: &[u8], + f: &dyn Fn(&CStr) -> io::Result, +) -> io::Result { + let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); + let buf_ptr = buf.as_mut_ptr() as *mut u8; + + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len()); + buf_ptr.add(bytes.len()).write(0); + } + + match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) { + Ok(s) => f(s), + Err(_) => Err(NUL_ERR), + } +} + +#[cold] +#[inline(never)] +fn run_with_cstr_allocating(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result) -> io::Result { + match CString::new(bytes) { + Ok(s) => f(&s), + Err(_) => Err(NUL_ERR), + } +} diff --git a/crates/std/src/sys/helpers/tests.rs b/crates/std/src/sys/helpers/tests.rs new file mode 100644 index 0000000..b67fdb9 --- /dev/null +++ b/crates/std/src/sys/helpers/tests.rs @@ -0,0 +1,73 @@ +use core::iter::repeat; + +use super::mul_div_u64; +use super::small_c_string::run_path_with_cstr; +use crate::ffi::CString; +use crate::hint::black_box; +use crate::path::Path; + +#[test] +fn stack_allocation_works() { + let path = Path::new("abc"); + let result = run_path_with_cstr(path, &|p| { + assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap()); + Ok(42) + }); + assert_eq!(result.unwrap(), 42); +} + +#[test] +fn stack_allocation_fails() { + let path = Path::new("ab\0"); + assert!(run_path_with_cstr::<()>(path, &|_| unreachable!()).is_err()); +} + +#[test] +fn heap_allocation_works() { + let path = repeat("a").take(384).collect::(); + let path = Path::new(&path); + let result = run_path_with_cstr(path, &|p| { + assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap()); + Ok(42) + }); + assert_eq!(result.unwrap(), 42); +} + +#[test] +fn heap_allocation_fails() { + let mut path = repeat("a").take(384).collect::(); + path.push('\0'); + let path = Path::new(&path); + assert!(run_path_with_cstr::<()>(path, &|_| unreachable!()).is_err()); +} + +#[bench] +fn bench_stack_path_alloc(b: &mut test::Bencher) { + let path = repeat("a").take(383).collect::(); + let p = Path::new(&path); + b.iter(|| { + run_path_with_cstr(p, &|cstr| { + black_box(cstr); + Ok(()) + }) + .unwrap(); + }); +} + +#[bench] +fn bench_heap_path_alloc(b: &mut test::Bencher) { + let path = repeat("a").take(384).collect::(); + let p = Path::new(&path); + b.iter(|| { + run_path_with_cstr(p, &|cstr| { + black_box(cstr); + Ok(()) + }) + .unwrap(); + }); +} + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); +} diff --git a/crates/std/src/sys/helpers/wstr.rs b/crates/std/src/sys/helpers/wstr.rs new file mode 100644 index 0000000..9c4b8e0 --- /dev/null +++ b/crates/std/src/sys/helpers/wstr.rs @@ -0,0 +1,59 @@ +//! This module contains constructs to work with 16-bit characters (UCS-2 or UTF-16) + +use crate::marker::PhantomData; +use crate::num::NonZero; +use crate::ptr::NonNull; + +/// A safe iterator over a LPWSTR +/// (aka a pointer to a series of UTF-16 code units terminated by a NULL). +pub struct WStrUnits<'a> { + // The pointer must never be null... + lpwstr: NonNull, + // ...and the memory it points to must be valid for this lifetime. + lifetime: PhantomData<&'a [u16]>, +} + +impl WStrUnits<'_> { + /// Creates the iterator. Returns `None` if `lpwstr` is null. + /// + /// SAFETY: `lpwstr` must point to a null-terminated wide string that lives + /// at least as long as the lifetime of this struct. + pub unsafe fn new(lpwstr: *const u16) -> Option { + Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData }) + } + + pub fn peek(&self) -> Option> { + // SAFETY: It's always safe to read the current item because we don't + // ever move out of the array's bounds. + unsafe { NonZero::new(*self.lpwstr.as_ptr()) } + } + + /// Advance the iterator while `predicate` returns true. + /// Returns the number of items it advanced by. + pub fn advance_while) -> bool>(&mut self, mut predicate: P) -> usize { + let mut counter = 0; + while let Some(w) = self.peek() { + if !predicate(w) { + break; + } + counter += 1; + self.next(); + } + counter + } +} + +impl Iterator for WStrUnits<'_> { + // This can never return zero as that marks the end of the string. + type Item = NonZero; + + fn next(&mut self) -> Option { + // SAFETY: If NULL is reached we immediately return. + // Therefore it's safe to advance the pointer after that. + unsafe { + let next = self.peek()?; + self.lpwstr = NonNull::new_unchecked(self.lpwstr.as_ptr().add(1)); + Some(next) + } + } +} diff --git a/crates/std/src/sys/mod.rs b/crates/std/src/sys/mod.rs index 05b3df0..dfd7ac2 100644 --- a/crates/std/src/sys/mod.rs +++ b/crates/std/src/sys/mod.rs @@ -19,7 +19,8 @@ pub mod thread; pub mod thread_local; pub mod time; pub use pal::*; -// pub mod fs; +pub mod fs; +pub mod helpers; /// A trait for viewing representations from std types. #[cfg_attr(not(target_os = "linux"), allow(unused))] diff --git a/crates/std/src/sys/os_str/bytes.rs b/crates/std/src/sys/os_str/bytes.rs index 1f9983f..449a504 100644 --- a/crates/std/src/sys/os_str/bytes.rs +++ b/crates/std/src/sys/os_str/bytes.rs @@ -7,7 +7,7 @@ use crate::borrow::Cow; use crate::bstr::ByteStr; use alloc_crate::collections::TryReserveError; use crate::rc::Rc; -use alloc_crate::sync::Arc; +use crate::sync::Arc; use crate::sys::{AsInner, FromInner, IntoInner}; use crate::{fmt, mem, str}; diff --git a/crates/std/src/sys/pal/unsupported/os.rs b/crates/std/src/sys/pal/unsupported/os.rs index 9956845..fe8adde 100644 --- a/crates/std/src/sys/pal/unsupported/os.rs +++ b/crates/std/src/sys/pal/unsupported/os.rs @@ -55,7 +55,3 @@ pub fn temp_dir() -> PathBuf { pub fn home_dir() -> Option { None } - -pub fn getpid() -> u32 { - panic!("no pids on this platform") -} diff --git a/crates/std/src/sys/path/mod.rs b/crates/std/src/sys/path/mod.rs index 254683b..bbb7577 100644 --- a/crates/std/src/sys/path/mod.rs +++ b/crates/std/src/sys/path/mod.rs @@ -1,3 +1,22 @@ +// There's a lot of necessary redundancy in separator definition. Consolidated into a macro to +// prevent transcription errors. +macro_rules! path_separator_bytes { + ($($sep:literal),+) => ( + pub const SEPARATORS: &[char] = &[$($sep as char,)+]; + pub const SEPARATORS_STR: &[&str] = &[$( + match str::from_utf8(&[$sep]) { + Ok(s) => s, + Err(_) => panic!("path_separator_bytes must be ASCII bytes"), + } + ),+]; + + #[inline] + pub const fn is_sep_byte(b: u8) -> bool { + $(b == $sep) ||+ + } + ) +} + cfg_select! { target_os = "windows" => { mod windows; diff --git a/crates/std/src/sys/path/unix.rs b/crates/std/src/sys/path/unix.rs index 611d250..b49c39a 100644 --- a/crates/std/src/sys/path/unix.rs +++ b/crates/std/src/sys/path/unix.rs @@ -2,14 +2,11 @@ use crate::ffi::OsStr; use crate::path::{Path, PathBuf, Prefix}; use crate::{env, io}; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} +path_separator_bytes!(b'/'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } #[inline] @@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = false; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; /// Make a POSIX path absolute without changing its semantics. pub(crate) fn absolute(path: &Path) -> io::Result { diff --git a/crates/std/src/sys/process/mod.rs b/crates/std/src/sys/process/mod.rs index 121d3bc..46f4ebf 100644 --- a/crates/std/src/sys/process/mod.rs +++ b/crates/std/src/sys/process/mod.rs @@ -27,9 +27,11 @@ cfg_select! { mod env; pub use env::CommandEnvs; +#[cfg(target_family = "unix")] +pub use imp::getppid; pub use imp::{ ChildPipe, Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, - read_output, + getpid, read_output, }; #[cfg(any( diff --git a/crates/std/src/sys/process/unsupported.rs b/crates/std/src/sys/process/unsupported.rs index a279d1c..9ed66a5 100644 --- a/crates/std/src/sys/process/unsupported.rs +++ b/crates/std/src/sys/process/unsupported.rs @@ -4,7 +4,7 @@ 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::fs::File; use crate::sys::unsupported; use crate::{fmt, io}; @@ -30,8 +30,8 @@ pub enum Stdio { MakePipe, ParentStdout, ParentStderr, - // #[allow(dead_code)] // This variant exists only for the Debug impl - // InheritFile(File), + #[allow(dead_code)] // This variant exists only for the Debug impl + InheritFile(File), } impl Command { @@ -124,20 +124,18 @@ impl From for Stdio { } } -// impl From for Stdio { -// fn from(file: File) -> Stdio { -// Stdio::InheritFile(file) -// } -// } +impl From for Stdio { + fn from(file: File) -> Stdio { + Stdio::InheritFile(file) + } +} impl fmt::Debug for Command { // show all attributes fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { let mut debug_command = f.debug_struct("Command"); - debug_command - .field("program", &self.program) - .field("args", &self.args); + debug_command.field("program", &self.program).field("args", &self.args); if !self.env.is_unchanged() { debug_command.field("env", &self.env); } @@ -329,3 +327,7 @@ pub fn read_output( ) -> io::Result<()> { match out.diverge() {} } + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff --git a/crates/std/src/sys/sync/once/mod.rs b/crates/std/src/sys/sync/once/mod.rs index aeea884..5796c6d 100644 --- a/crates/std/src/sys/sync/once/mod.rs +++ b/crates/std/src/sys/sync/once/mod.rs @@ -12,7 +12,7 @@ cfg_select! { all(target_os = "windows", not(target_vendor="win7")), target_os = "linux", target_os = "android", - all(target_arch = "wasm32", target_feature = "atomics"), + all(target_family = "wasm", target_feature = "atomics"), target_os = "freebsd", target_os = "motor", target_os = "openbsd", diff --git a/crates/std/src/sys/sync/once/no_threads.rs b/crates/std/src/sys/sync/once/no_threads.rs index 576bbf6..42fe241 100644 --- a/crates/std/src/sys/sync/once/no_threads.rs +++ b/crates/std/src/sys/sync/once/no_threads.rs @@ -39,6 +39,11 @@ impl Once { Once { state: Cell::new(State::Incomplete) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state: Cell::new(State::Complete) } + } + #[inline] pub fn is_completed(&self) -> bool { self.state.get() == State::Complete diff --git a/crates/std/src/sys/sync/thread_parking/mod.rs b/crates/std/src/sys/sync/thread_parking/mod.rs index 74b5b72..9d5a0a9 100644 --- a/crates/std/src/sys/sync/thread_parking/mod.rs +++ b/crates/std/src/sys/sync/thread_parking/mod.rs @@ -3,7 +3,7 @@ cfg_select! { all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", - all(target_arch = "wasm32", target_feature = "atomics"), + all(target_family = "wasm", target_feature = "atomics"), target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", diff --git a/crates/std/src/thread.rs b/crates/std/src/thread.rs index da581ad..43c9802 100644 --- a/crates/std/src/thread.rs +++ b/crates/std/src/thread.rs @@ -17,6 +17,7 @@ pub use current::current_id; pub(crate) use current::current_or_unnamed; pub(crate) use current::current_os_id; pub(crate) use current::with_current_name; +pub(crate) use current::drop_current; pub use functions::sleep; pub use id::ThreadId; pub(crate) use lifecycle::ThreadInit; diff --git a/crates/std/src/thread/functions.rs b/crates/std/src/thread/functions.rs index 95d7aaf..7064210 100644 --- a/crates/std/src/thread/functions.rs +++ b/crates/std/src/thread/functions.rs @@ -168,7 +168,11 @@ pub fn yield_now() { imp::yield_now() } -/// Determines whether the current thread is unwinding because of panic. +/// Determines whether the current thread is panicking. +/// +/// This returns `true` both when the thread is unwinding due to a panic, +/// or executing a panic hook. Note that the latter case will still happen +/// when `panic=abort` is set. /// /// A common use of this feature is to poison shared resources when writing /// unsafe code, by checking `panicking` when the `drop` is called. @@ -309,14 +313,14 @@ pub fn sleep(dur: Duration) { /// /// | Platform | System call | /// |-----------|----------------------------------------------------------------------| -/// | Linux | [clock_nanosleep] (Monotonic clock) | -/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] | -/// | Android | [clock_nanosleep] (Monotonic Clock)] | -/// | Solaris | [clock_nanosleep] (Monotonic Clock)] | -/// | Illumos | [clock_nanosleep] (Monotonic Clock)] | -/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] | -/// | Hurd | [clock_nanosleep] (Monotonic Clock)] | -/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] | +/// | Linux | [clock_nanosleep] (Monotonic Clock) | +/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock) | +/// | Android | [clock_nanosleep] (Monotonic Clock) | +/// | Solaris | [clock_nanosleep] (Monotonic Clock) | +/// | Illumos | [clock_nanosleep] (Monotonic Clock) | +/// | Dragonfly | [clock_nanosleep] (Monotonic Clock) | +/// | Hurd | [clock_nanosleep] (Monotonic Clock) | +/// | Vxworks | [clock_nanosleep] (Monotonic Clock) | /// | Apple | `mach_wait_until` | /// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself | /// diff --git a/crates/std/src/thread/lifecycle.rs b/crates/std/src/thread/lifecycle.rs index 3a7e65f..0bb1f34 100644 --- a/crates/std/src/thread/lifecycle.rs +++ b/crates/std/src/thread/lifecycle.rs @@ -8,7 +8,7 @@ use super::{Result, spawnhook}; use crate::cell::UnsafeCell; use crate::marker::PhantomData; use crate::mem::{ManuallyDrop, MaybeUninit}; -use alloc_crate::sync::Arc; +use crate::sync::Arc; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::{AsInner, IntoInner, thread as imp}; use crate::{env, io, panic}; diff --git a/crates/std/src/thread/scoped.rs b/crates/std/src/thread/scoped.rs index 6c7e0cb..929f7fd 100644 --- a/crates/std/src/thread/scoped.rs +++ b/crates/std/src/thread/scoped.rs @@ -5,7 +5,7 @@ use super::lifecycle::{JoinInner, spawn_unchecked}; use super::thread::Thread; use crate::marker::PhantomData; use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; -use alloc_crate::sync::Arc; +use crate::sync::Arc; use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering}; use crate::{fmt, io}; diff --git a/crates/std/src/thread/spawnhook.rs b/crates/std/src/thread/spawnhook.rs index a4a03e7..254793a 100644 --- a/crates/std/src/thread/spawnhook.rs +++ b/crates/std/src/thread/spawnhook.rs @@ -1,7 +1,7 @@ use super::thread::Thread; use crate::cell::Cell; use crate::iter; -use alloc_crate::sync::Arc; +use crate::sync::Arc; crate::thread_local! { /// A thread local linked list of spawn hooks. diff --git a/crates/std/src/thread/thread.rs b/crates/std/src/thread/thread.rs index ee1151c..7c9c91c 100644 --- a/crates/std/src/thread/thread.rs +++ b/crates/std/src/thread/thread.rs @@ -4,7 +4,7 @@ use crate::alloc::System; use crate::ffi::CStr; use crate::fmt; use crate::pin::Pin; -use alloc_crate::sync::Arc; +use crate::sync::Arc; use crate::sys::sync::Parker; use crate::time::Duration;