Add more from the std
This commit is contained in:
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -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
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
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]
|
[package]
|
||||||
name = "kernel-rust"
|
name = "kernel-rust"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#![feature(iterator_try_collect, iter_order_by)]
|
#![feature(iterator_try_collect, iter_order_by)]
|
||||||
|
#![allow(unused_features)]
|
||||||
#![cfg_attr(any(not(feature = "std"), target_arch = "riscv64"), no_std)]
|
#![cfg_attr(any(not(feature = "std"), target_arch = "riscv64"), no_std)]
|
||||||
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[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"
|
hashbrown = "0.16"
|
||||||
os-std-macros = { path = "../os-std-macros" }
|
os-std-macros = { path = "../os-std-macros" }
|
||||||
shared = { path = "../shared", features = ["user"] }
|
shared = { path = "../shared", features = ["user"] }
|
||||||
|
|||||||
1
crates/std/crates/backtrace-rs
Submodule
1
crates/std/crates/backtrace-rs
Submodule
Submodule crates/std/crates/backtrace-rs added at 28ec93b503
@@ -28,17 +28,29 @@ cp_std path:
|
|||||||
|
|
||||||
setup-std:
|
setup-std:
|
||||||
@# Not copied : sys/mod.rs, io.rs, error.rs, thread.rs, sync.rs
|
@# 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 "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 "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 "time.rs"
|
||||||
|
|
||||||
@just cp_std "os/mod.rs"
|
@just cp_std "os/mod.rs"
|
||||||
@just cp_std "os/raw/mod.rs"
|
@just cp_std "os/raw/mod.rs"
|
||||||
@just cp_std "os/raw/tests.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/map.rs"
|
||||||
@just cp_std "collections/hash/set.rs"
|
@just cp_std "collections/hash/set.rs"
|
||||||
@just cp_std "collections/hash/mod.rs"
|
@just cp_std "collections/hash/mod.rs"
|
||||||
@@ -114,6 +126,7 @@ setup-std:
|
|||||||
@just cp_std "sys/cmath.rs"
|
@just cp_std "sys/cmath.rs"
|
||||||
@just cp_std "sys/process/mod.rs"
|
@just cp_std "sys/process/mod.rs"
|
||||||
@just cp_std "sys/process/env.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/mod.rs"
|
||||||
@just cp_std "sys/args/unsupported.rs"
|
@just cp_std "sys/args/unsupported.rs"
|
||||||
@just cp_std "sys/pal/mod.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/stdio/unsupported.rs"
|
||||||
@just cp_std "sys/alloc/mod.rs"
|
@just cp_std "sys/alloc/mod.rs"
|
||||||
@just cp_std "sys/backtrace.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
|
@# Copied but edited for the moment
|
||||||
# @just cp_std "sys/process/unsupported.rs"
|
|
||||||
# @just cp_std "path.rs"
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
s|crate::collections::TryReserveError|alloc_crate::collections::TryReserveError|g
|
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::ffi|alloc_crate::ffi|g
|
||||||
s|alloc::slice::Join|alloc_crate::slice::Join|g
|
s|alloc::slice::Join|alloc_crate::slice::Join|g
|
||||||
s|alloc::bstr|alloc_crate::bstr|g
|
s|alloc::bstr|alloc_crate::bstr|g
|
||||||
|
|||||||
210
crates/std/src/ascii.rs
Normal file
210
crates/std/src/ascii.rs
Normal file
@@ -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<u8>;
|
||||||
|
|
||||||
|
delegating_ascii_methods!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
impl AsciiExt for str {
|
||||||
|
type Owned = String;
|
||||||
|
|
||||||
|
delegating_ascii_methods!();
|
||||||
|
}
|
||||||
478
crates/std/src/backtrace.rs
Normal file
478
crates/std/src/backtrace.rs
Normal file
@@ -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<Capture, LazyResolve>),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Capture {
|
||||||
|
actual_start: usize,
|
||||||
|
frames: Vec<BacktraceFrame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _assert_send_sync() {
|
||||||
|
fn _assert<T: Send + Sync>() {}
|
||||||
|
_assert::<Backtrace>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single frame of a backtrace.
|
||||||
|
#[unstable(feature = "backtrace_frames", issue = "79676")]
|
||||||
|
pub struct BacktraceFrame {
|
||||||
|
frame: RawFrame,
|
||||||
|
symbols: Vec<BacktraceSymbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum RawFrame {
|
||||||
|
Actual(backtrace_rs::Frame),
|
||||||
|
#[cfg(test)]
|
||||||
|
Fake,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BacktraceSymbol {
|
||||||
|
name: Option<Vec<u8>>,
|
||||||
|
filename: Option<BytesOrWide>,
|
||||||
|
lineno: Option<u32>,
|
||||||
|
colno: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BytesOrWide {
|
||||||
|
Bytes(Vec<u8>),
|
||||||
|
Wide(Vec<u16>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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("<unsupported>"),
|
||||||
|
Inner::Disabled => return fmt.write_str("<disabled>"),
|
||||||
|
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: <unknown>")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u8> = 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -357,6 +357,7 @@ impl<K, V, S> HashMap<K, V, S> {
|
|||||||
/// map.insert(1, 2);
|
/// map.insert(1, 2);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||||
#[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")]
|
#[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")]
|
||||||
pub const fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
|
pub const fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
|
||||||
@@ -389,6 +390,7 @@ impl<K, V, S> HashMap<K, V, S> {
|
|||||||
/// map.insert(1, 2);
|
/// map.insert(1, 2);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||||
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap<K, V, S> {
|
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap<K, V, S> {
|
||||||
HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) }
|
HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) }
|
||||||
@@ -409,6 +411,7 @@ impl<K, V, S, A: Allocator> HashMap<K, V, S, A> {
|
|||||||
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
|
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
|
||||||
/// the `HashMap` to be useful, see its documentation for details.
|
/// the `HashMap` to be useful, see its documentation for details.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self {
|
pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self {
|
||||||
HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) }
|
HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) }
|
||||||
@@ -430,6 +433,7 @@ impl<K, V, S, A: Allocator> HashMap<K, V, S, A> {
|
|||||||
/// the `HashMap` to be useful, see its documentation for details.
|
/// the `HashMap` to be useful, see its documentation for details.
|
||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self {
|
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) }
|
HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) }
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ impl<T, S> HashSet<T, S> {
|
|||||||
/// set.insert(2);
|
/// set.insert(2);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||||
#[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")]
|
#[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")]
|
||||||
pub const fn with_hasher(hasher: S) -> HashSet<T, S> {
|
pub const fn with_hasher(hasher: S) -> HashSet<T, S> {
|
||||||
@@ -261,6 +262,7 @@ impl<T, S> HashSet<T, S> {
|
|||||||
/// set.insert(1);
|
/// set.insert(1);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||||
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
|
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
|
||||||
HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) }
|
HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) }
|
||||||
@@ -281,6 +283,7 @@ impl<T, S, A: Allocator> HashSet<T, S, A> {
|
|||||||
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
|
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
|
||||||
/// the `HashSet` to be useful, see its documentation for details.
|
/// the `HashSet` to be useful, see its documentation for details.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet<T, S, A> {
|
pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet<T, S, A> {
|
||||||
HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) }
|
HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) }
|
||||||
@@ -301,6 +304,7 @@ impl<T, S, A: Allocator> HashSet<T, S, A> {
|
|||||||
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
|
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
|
||||||
/// the `HashSet` to be useful, see its documentation for details.
|
/// the `HashSet` to be useful, see its documentation for details.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet<T, S, A> {
|
pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet<T, S, A> {
|
||||||
HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) }
|
HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) }
|
||||||
|
|||||||
@@ -670,6 +670,17 @@ pub fn home_dir() -> Option<PathBuf> {
|
|||||||
///
|
///
|
||||||
/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
|
/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
|
||||||
/// [`GetTempPath`][GetTempPath], which this function uses internally.
|
/// [`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].
|
/// Note that, this [may change in the future][changes].
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,4 +1,562 @@
|
|||||||
|
// todo retreive docs
|
||||||
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use core::error::Error;
|
pub use core::error::Error;
|
||||||
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
||||||
pub use core::error::{Request, request_ref, request_value};
|
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<SuperError>> {
|
||||||
|
/// 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<SuperError>> {
|
||||||
|
/// 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<E = Box<dyn Error>> {
|
||||||
|
/// 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<E> Report<E>
|
||||||
|
where
|
||||||
|
Report<E>: From<E>,
|
||||||
|
{
|
||||||
|
/// Creates a new `Report` from an input error.
|
||||||
|
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||||
|
pub fn new(error: E) -> Report<E> {
|
||||||
|
Self::from(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Report<E> {
|
||||||
|
/// 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::<Backtrace>(&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<E> Report<E>
|
||||||
|
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(<dyn Error>::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<E> From<E> for Report<E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
fn from(error: E) -> Self {
|
||||||
|
Report { error, show_backtrace: false, pretty: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||||
|
impl<E> fmt::Display for Report<E>
|
||||||
|
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<E> fmt::Debug for Report<E>
|
||||||
|
where
|
||||||
|
Report<E>: 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<T> 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::hash::{Hash, Hasher};
|
|||||||
use crate::ops::{self, Range};
|
use crate::ops::{self, Range};
|
||||||
use crate::rc::Rc;
|
use crate::rc::Rc;
|
||||||
use crate::str::FromStr;
|
use crate::str::FromStr;
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sys::os_str::{Buf, Slice};
|
use crate::sys::os_str::{Buf, Slice};
|
||||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||||
use crate::{cmp, fmt, slice};
|
use crate::{cmp, fmt, slice};
|
||||||
@@ -576,15 +576,21 @@ impl OsString {
|
|||||||
|
|
||||||
/// Truncate the `OsString` to the specified length.
|
/// Truncate the `OsString` to the specified length.
|
||||||
///
|
///
|
||||||
|
/// If `new_len` is greater than the string's current length, this has no
|
||||||
|
/// effect.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
///
|
||||||
/// Panics if `len` does not lie on a valid `OsStr` boundary
|
/// Panics if `len` does not lie on a valid `OsStr` boundary
|
||||||
/// (as described in [`OsStr::slice_encoded_bytes`]).
|
/// (as described in [`OsStr::slice_encoded_bytes`]).
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "os_string_truncate", issue = "133262")]
|
#[unstable(feature = "os_string_truncate", issue = "133262")]
|
||||||
pub fn truncate(&mut self, len: usize) {
|
pub fn truncate(&mut self, len: usize) {
|
||||||
self.as_os_str().inner.check_public_boundary(len);
|
if len <= self.len() {
|
||||||
// SAFETY: The length was just checked to be at a valid boundary.
|
self.as_os_str().inner.check_public_boundary(len);
|
||||||
unsafe { self.inner.truncate_unchecked(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
|
/// Provides plumbing to `Vec::extend_from_slice` without giving full
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
target_os = "wasi",
|
target_os = "wasi",
|
||||||
target_env = "sgx",
|
target_env = "sgx",
|
||||||
target_os = "xous",
|
target_os = "xous",
|
||||||
target_os = "survos",
|
|
||||||
target_os = "trusty",
|
target_os = "trusty",
|
||||||
))
|
))
|
||||||
))]
|
))]
|
||||||
@@ -46,7 +45,7 @@ use crate::ffi::OsString;
|
|||||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||||
use crate::path::{Path, PathBuf};
|
use crate::path::{Path, PathBuf};
|
||||||
use crate::sealed::Sealed;
|
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::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp};
|
||||||
use crate::time::SystemTime;
|
use crate::time::SystemTime;
|
||||||
use crate::{error, fmt};
|
use crate::{error, fmt};
|
||||||
@@ -2681,7 +2680,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
|
|||||||
///
|
///
|
||||||
/// This function will only ever return an error of kind `NotFound` if the given
|
/// 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,
|
/// 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.
|
/// such as insufficient permissions.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@@ -3151,7 +3150,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||||||
///
|
///
|
||||||
/// This function will only ever return an error of kind `NotFound` if the given
|
/// 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,
|
/// 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.
|
/// such as insufficient permissions.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|||||||
@@ -21,12 +21,14 @@ pub use core::io::{BorrowedBuf, BorrowedCursor};
|
|||||||
use core::slice::memchr;
|
use core::slice::memchr;
|
||||||
pub use cursor::Cursor;
|
pub use cursor::Cursor;
|
||||||
|
|
||||||
pub use self::stdio::{
|
pub use self::copy::copy;
|
||||||
Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout,
|
|
||||||
};
|
|
||||||
pub use self::pipe::{PipeReader, PipeWriter};
|
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(crate) use stdio::attempt_print_to_stderr;
|
||||||
|
pub use stdio::try_set_output_capture;
|
||||||
|
|
||||||
use crate::fs::File;
|
use crate::fs::File;
|
||||||
use io::IoBase;
|
use io::IoBase;
|
||||||
@@ -43,7 +45,7 @@ impl IoBase for Stdin {
|
|||||||
|
|
||||||
impl io::Read for Stdin {
|
impl io::Read for Stdin {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
|
fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
|
||||||
unsafe { File::from_raw_fd(0).read(buf) }
|
unsafe { crate::other_fs::File::from_raw_fd(0).read(buf) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2754
crates/std/src/keyword_docs.rs
Normal file
2754
crates/std/src/keyword_docs.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
|||||||
#![allow(unused_lifetimes)]
|
#![allow(unused_lifetimes)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![deny(fuzzy_provenance_casts)]
|
#![deny(fuzzy_provenance_casts)]
|
||||||
|
#![allow(fuzzy_provenance_casts)]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
#![allow(rustdoc::redundant_explicit_links)]
|
#![allow(rustdoc::redundant_explicit_links)]
|
||||||
#![warn(rustdoc::unescaped_backticks)]
|
#![warn(rustdoc::unescaped_backticks)]
|
||||||
@@ -265,7 +266,7 @@ pub use alloc_crate::vec;
|
|||||||
pub use core::{
|
pub use core::{
|
||||||
assert, cfg, column, compile_error, concat, const_format_args, env, file, format_args,
|
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,
|
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]
|
#[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 ffi;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
// pub mod fs;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod num;
|
pub mod num;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
@@ -285,17 +285,25 @@ pub mod process;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod rt;
|
pub mod rt;
|
||||||
pub mod alloc;
|
pub mod alloc;
|
||||||
|
pub mod ascii;
|
||||||
|
pub mod backtrace;
|
||||||
pub mod bstr;
|
pub mod bstr;
|
||||||
pub mod collections;
|
pub mod collections;
|
||||||
pub mod env;
|
pub mod env;
|
||||||
|
pub mod fs;
|
||||||
|
pub mod keyword_docs;
|
||||||
|
pub mod macros;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
pub mod panicking;
|
pub mod panicking;
|
||||||
|
pub mod pat;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub use backtrace_rs;
|
|
||||||
|
#[path = "../crates/backtrace-rs/src/lib.rs"]
|
||||||
|
mod backtrace_rs;
|
||||||
|
|
||||||
#[prelude_import]
|
#[prelude_import]
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@@ -310,23 +318,23 @@ mod sealed {
|
|||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use shared::fs;
|
pub use shared::fs as other_fs;
|
||||||
pub use shared::syscall;
|
pub use shared::syscall;
|
||||||
|
|
||||||
#[macro_export]
|
// #[macro_export]
|
||||||
macro_rules! print {
|
// macro_rules! print {
|
||||||
($($args:expr),*) => {
|
// ($($args:expr),*) => {
|
||||||
$crate::syscall::write_string_temp(&format!($($args),*))
|
// $crate::syscall::write_string_temp(&format!($($args),*))
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
#[macro_export]
|
// #[macro_export]
|
||||||
macro_rules! println {
|
// macro_rules! println {
|
||||||
() => {
|
// () => {
|
||||||
$crate::print!("");
|
// $crate::print!("");
|
||||||
// $crate::print!("\n\r");
|
// // $crate::print!("\n\r");
|
||||||
};
|
// };
|
||||||
($($args:expr),*) => {
|
// ($($args:expr),*) => {
|
||||||
$crate::print!($($args),*);
|
// $crate::print!($($args),*);
|
||||||
// $crate::println!();
|
// // $crate::println!();
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|||||||
416
crates/std/src/macros.rs
Normal file
416
crates/std/src/macros.rs
Normal file
@@ -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),*)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
3
crates/std/src/pat.rs
Normal file
3
crates/std/src/pat.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
//! Helper module for exporting the `pattern_type` macro
|
||||||
|
|
||||||
|
pub use core::pattern_type;
|
||||||
@@ -92,8 +92,8 @@ use crate::iter::FusedIterator;
|
|||||||
use crate::ops::{self, Deref};
|
use crate::ops::{self, Deref};
|
||||||
use crate::rc::Rc;
|
use crate::rc::Rc;
|
||||||
use crate::str::FromStr;
|
use crate::str::FromStr;
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix};
|
use crate::sys::path::{HAS_PREFIXES, is_sep_byte, is_verbatim_sep, parse_prefix};
|
||||||
use crate::{cmp, fmt, fs, io, sys};
|
use crate::{cmp, fmt, fs, io, sys};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -266,22 +266,33 @@ impl<'a> Prefix<'a> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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)
|
c.is_ascii() && is_sep_byte(c as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The primary separator of path components for the current platform.
|
/// All path separators recognized on the current platform, represented as [`char`]s; for example,
|
||||||
///
|
/// this is `&['/'][..]` on Unix and `&['\\', '/'][..]` on Windows. The [primary
|
||||||
/// For example, `/` on Unix and `\` on Windows.
|
/// 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")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[cfg_attr(not(test), rustc_diagnostic_item = "path_main_separator")]
|
#[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.
|
/// The primary separator of path components for the current platform, represented as a [`&str`];
|
||||||
///
|
/// for example, this is `"/"` on Unix and `"\\"` on Windows.
|
||||||
/// For example, `/` on Unix and `\` on Windows.
|
|
||||||
#[stable(feature = "main_separator_str", since = "1.68.0")]
|
#[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
|
// Misc helpers
|
||||||
@@ -562,7 +573,7 @@ impl<'a> Component<'a> {
|
|||||||
pub fn as_os_str(self) -> &'a OsStr {
|
pub fn as_os_str(self) -> &'a OsStr {
|
||||||
match self {
|
match self {
|
||||||
Component::Prefix(p) => p.as_os_str(),
|
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::CurDir => OsStr::new("."),
|
||||||
Component::ParentDir => OsStr::new(".."),
|
Component::ParentDir => OsStr::new(".."),
|
||||||
Component::Normal(path) => path,
|
Component::Normal(path) => path,
|
||||||
@@ -1379,7 +1390,7 @@ impl PathBuf {
|
|||||||
|
|
||||||
for c in buf {
|
for c in buf {
|
||||||
if need_sep && c != Component::RootDir {
|
if need_sep && c != Component::RootDir {
|
||||||
res.push(MAIN_SEP_STR);
|
res.push(MAIN_SEPARATOR_STR);
|
||||||
}
|
}
|
||||||
res.push(c.as_os_str());
|
res.push(c.as_os_str());
|
||||||
|
|
||||||
@@ -1402,7 +1413,7 @@ impl PathBuf {
|
|||||||
|
|
||||||
// `path` is a pure relative path
|
// `path` is a pure relative path
|
||||||
} else if need_sep {
|
} else if need_sep {
|
||||||
self.inner.push(MAIN_SEP_STR);
|
self.inner.push(MAIN_SEPARATOR_STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner.push(path);
|
self.inner.push(path);
|
||||||
@@ -3240,73 +3251,101 @@ impl Path {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Queries the file system to get information about a file, directory, etc.
|
/// Queries the file system to get information about a file, directory, etc.
|
||||||
// ///
|
///
|
||||||
// /// This function will traverse symbolic links to query information about the
|
/// This function will traverse symbolic links to query information about the
|
||||||
// /// destination file.
|
/// destination file.
|
||||||
// ///
|
///
|
||||||
// /// This is an alias to [`fs::metadata`].
|
/// This is an alias to [`fs::metadata`].
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// ///
|
///
|
||||||
// /// let path = Path::new("/Minas/tirith");
|
/// let path = Path::new("/Minas/tirith");
|
||||||
// /// let metadata = path.metadata().expect("metadata call failed");
|
/// let metadata = path.metadata().expect("metadata call failed");
|
||||||
// /// println!("{:?}", metadata.file_type());
|
/// println!("{:?}", metadata.file_type());
|
||||||
// /// ```
|
/// ```
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn metadata(&self) -> io::Result<fs::Metadata> {
|
pub fn metadata(&self) -> io::Result<fs::Metadata> {
|
||||||
// fs::metadata(self)
|
fs::metadata(self)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Queries the metadata about a file without following symlinks.
|
/// Queries the metadata about a file without following symlinks.
|
||||||
// ///
|
///
|
||||||
// /// This is an alias to [`fs::symlink_metadata`].
|
/// This is an alias to [`fs::symlink_metadata`].
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// ///
|
///
|
||||||
// /// let path = Path::new("/Minas/tirith");
|
/// let path = Path::new("/Minas/tirith");
|
||||||
// /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
|
/// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
|
||||||
// /// println!("{:?}", metadata.file_type());
|
/// println!("{:?}", metadata.file_type());
|
||||||
// /// ```
|
/// ```
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
|
pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
|
||||||
// fs::symlink_metadata(self)
|
fs::symlink_metadata(self)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Returns the canonical, absolute form of the path with all intermediate
|
/// Returns the canonical, absolute form of the path with all intermediate
|
||||||
// /// components normalized and symbolic links resolved.
|
/// components normalized and symbolic links resolved.
|
||||||
// ///
|
///
|
||||||
// /// This is an alias to [`fs::canonicalize`].
|
/// This is an alias to [`fs::canonicalize`].
|
||||||
// ///
|
///
|
||||||
// /// # Errors
|
/// # Errors
|
||||||
// ///
|
///
|
||||||
// /// This method will return an error in the following situations, but is not
|
/// This method will return an error in the following situations, but is not
|
||||||
// /// limited to just these cases:
|
/// limited to just these cases:
|
||||||
// ///
|
///
|
||||||
// /// * `path` does not exist.
|
/// * `path` does not exist.
|
||||||
// /// * A non-final component in path is not a directory.
|
/// * A non-final component in path is not a directory.
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::{Path, PathBuf};
|
/// use std::path::{Path, PathBuf};
|
||||||
// ///
|
///
|
||||||
// /// let path = Path::new("/foo/test/../test/bar.rs");
|
/// let path = Path::new("/foo/test/../test/bar.rs");
|
||||||
// /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
|
/// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
|
||||||
// /// ```
|
/// ```
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn canonicalize(&self) -> io::Result<PathBuf> {
|
pub fn canonicalize(&self) -> io::Result<PathBuf> {
|
||||||
// fs::canonicalize(self)
|
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<PathBuf> {
|
||||||
|
absolute(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Normalize a path, including `..` without traversing the filesystem.
|
/// Normalize a path, including `..` without traversing the filesystem.
|
||||||
///
|
///
|
||||||
@@ -3369,206 +3408,206 @@ impl Path {
|
|||||||
Ok(lexical)
|
Ok(lexical)
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Reads a symbolic link, returning the file that the link points to.
|
/// Reads a symbolic link, returning the file that the link points to.
|
||||||
// ///
|
///
|
||||||
// /// This is an alias to [`fs::read_link`].
|
/// This is an alias to [`fs::read_link`].
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// ///
|
///
|
||||||
// /// let path = Path::new("/laputa/sky_castle.rs");
|
/// let path = Path::new("/laputa/sky_castle.rs");
|
||||||
// /// let path_link = path.read_link().expect("read_link call failed");
|
/// let path_link = path.read_link().expect("read_link call failed");
|
||||||
// /// ```
|
/// ```
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn read_link(&self) -> io::Result<PathBuf> {
|
pub fn read_link(&self) -> io::Result<PathBuf> {
|
||||||
// fs::read_link(self)
|
fs::read_link(self)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Returns an iterator over the entries within a directory.
|
/// Returns an iterator over the entries within a directory.
|
||||||
// ///
|
///
|
||||||
// /// The iterator will yield instances of <code>[io::Result]<[fs::DirEntry]></code>. New
|
/// The iterator will yield instances of <code>[io::Result]<[fs::DirEntry]></code>. New
|
||||||
// /// errors may be encountered after an iterator is initially constructed.
|
/// errors may be encountered after an iterator is initially constructed.
|
||||||
// ///
|
///
|
||||||
// /// This is an alias to [`fs::read_dir`].
|
/// This is an alias to [`fs::read_dir`].
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// ///
|
///
|
||||||
// /// let path = Path::new("/laputa");
|
/// let path = Path::new("/laputa");
|
||||||
// /// for entry in path.read_dir().expect("read_dir call failed") {
|
/// for entry in path.read_dir().expect("read_dir call failed") {
|
||||||
// /// if let Ok(entry) = entry {
|
/// if let Ok(entry) = entry {
|
||||||
// /// println!("{:?}", entry.path());
|
/// println!("{:?}", entry.path());
|
||||||
// /// }
|
/// }
|
||||||
// /// }
|
/// }
|
||||||
// /// ```
|
/// ```
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
|
pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
|
||||||
// fs::read_dir(self)
|
fs::read_dir(self)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Returns `true` if the path points at an existing entity.
|
/// Returns `true` if the path points at an existing entity.
|
||||||
// ///
|
///
|
||||||
// /// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
|
/// 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.
|
/// 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
|
/// This function will traverse symbolic links to query information about the
|
||||||
// /// destination file.
|
/// destination file.
|
||||||
// ///
|
///
|
||||||
// /// If you cannot access the metadata of the file, e.g. because of a
|
/// If you cannot access the metadata of the file, e.g. because of a
|
||||||
// /// permission error or broken symbolic links, this will return `false`.
|
/// permission error or broken symbolic links, this will return `false`.
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// /// assert!(!Path::new("does_not_exist.txt").exists());
|
/// assert!(!Path::new("does_not_exist.txt").exists());
|
||||||
// /// ```
|
/// ```
|
||||||
// ///
|
///
|
||||||
// /// # See Also
|
/// # See Also
|
||||||
// ///
|
///
|
||||||
// /// This is a convenience function that coerces errors to false. If you want to
|
/// This is a convenience function that coerces errors to false. If you want to
|
||||||
// /// check errors, call [`Path::try_exists`].
|
/// check errors, call [`Path::try_exists`].
|
||||||
// ///
|
///
|
||||||
// /// [`try_exists()`]: Self::try_exists
|
/// [`try_exists()`]: Self::try_exists
|
||||||
// /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
/// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[must_use]
|
#[must_use]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn exists(&self) -> bool {
|
pub fn exists(&self) -> bool {
|
||||||
// fs::metadata(self).is_ok()
|
fs::metadata(self).is_ok()
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Returns `Ok(true)` if the path points at an existing entity.
|
/// Returns `Ok(true)` if the path points at an existing entity.
|
||||||
// ///
|
///
|
||||||
// /// This function will traverse symbolic links to query information about the
|
/// This function will traverse symbolic links to query information about the
|
||||||
// /// destination file. In case of broken symbolic links this will return `Ok(false)`.
|
/// 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
|
/// [`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
|
/// 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
|
/// 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
|
/// 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.
|
/// permission is denied on one of the parent directories.
|
||||||
// ///
|
///
|
||||||
// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
/// 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
|
/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
|
||||||
// /// where those bugs are not an issue.
|
/// where those bugs are not an issue.
|
||||||
// ///
|
///
|
||||||
// /// This is an alias for [`std::fs::exists`](crate::fs::exists).
|
/// This is an alias for [`std::fs::exists`](crate::fs::exists).
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// 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("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());
|
/// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
|
||||||
// /// ```
|
/// ```
|
||||||
// ///
|
///
|
||||||
// /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
/// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||||
// /// [`exists()`]: Self::exists
|
/// [`exists()`]: Self::exists
|
||||||
// #[stable(feature = "path_try_exists", since = "1.63.0")]
|
#[stable(feature = "path_try_exists", since = "1.63.0")]
|
||||||
// #[inline]
|
#[inline]
|
||||||
// pub fn try_exists(&self) -> io::Result<bool> {
|
pub fn try_exists(&self) -> io::Result<bool> {
|
||||||
// fs::exists(self)
|
fs::exists(self)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Returns `true` if the path exists on disk and is pointing at a regular file.
|
/// 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
|
/// This function will traverse symbolic links to query information about the
|
||||||
// /// destination file.
|
/// destination file.
|
||||||
// ///
|
///
|
||||||
// /// If you cannot access the metadata of the file, e.g. because of a
|
/// If you cannot access the metadata of the file, e.g. because of a
|
||||||
// /// permission error or broken symbolic links, this will return `false`.
|
/// permission error or broken symbolic links, this will return `false`.
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// /// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
|
/// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
|
||||||
// /// assert_eq!(Path::new("a_file.txt").is_file(), true);
|
/// assert_eq!(Path::new("a_file.txt").is_file(), true);
|
||||||
// /// ```
|
/// ```
|
||||||
// ///
|
///
|
||||||
// /// # See Also
|
/// # See Also
|
||||||
// ///
|
///
|
||||||
// /// This is a convenience function that coerces errors to false. If you want to
|
/// 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
|
/// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
|
||||||
// /// [`fs::Metadata::is_file`] if it was [`Ok`].
|
/// [`fs::Metadata::is_file`] if it was [`Ok`].
|
||||||
// ///
|
///
|
||||||
// /// When the goal is simply to read from (or write to) the source, the most
|
/// 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
|
/// 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
|
/// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
|
||||||
// /// a Unix-like system for example. See [`fs::File::open`] or
|
/// a Unix-like system for example. See [`fs::File::open`] or
|
||||||
// /// [`fs::OpenOptions::open`] for more information.
|
/// [`fs::OpenOptions::open`] for more information.
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[must_use]
|
#[must_use]
|
||||||
// pub fn is_file(&self) -> bool {
|
pub fn is_file(&self) -> bool {
|
||||||
// fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
|
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.
|
/// 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
|
/// This function will traverse symbolic links to query information about the
|
||||||
// /// destination file.
|
/// destination file.
|
||||||
// ///
|
///
|
||||||
// /// If you cannot access the metadata of the file, e.g. because of a
|
/// If you cannot access the metadata of the file, e.g. because of a
|
||||||
// /// permission error or broken symbolic links, this will return `false`.
|
/// permission error or broken symbolic links, this will return `false`.
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```no_run
|
/// ```no_run
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
|
/// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
|
||||||
// /// assert_eq!(Path::new("a_file.txt").is_dir(), false);
|
/// assert_eq!(Path::new("a_file.txt").is_dir(), false);
|
||||||
// /// ```
|
/// ```
|
||||||
// ///
|
///
|
||||||
// /// # See Also
|
/// # See Also
|
||||||
// ///
|
///
|
||||||
// /// This is a convenience function that coerces errors to false. If you want to
|
/// 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
|
/// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
|
||||||
// /// [`fs::Metadata::is_dir`] if it was [`Ok`].
|
/// [`fs::Metadata::is_dir`] if it was [`Ok`].
|
||||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||||
// #[must_use]
|
#[must_use]
|
||||||
// pub fn is_dir(&self) -> bool {
|
pub fn is_dir(&self) -> bool {
|
||||||
// fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
|
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.
|
/// Returns `true` if the path exists on disk and is pointing at a symbolic link.
|
||||||
// ///
|
///
|
||||||
// /// This function will not traverse symbolic links.
|
/// This function will not traverse symbolic links.
|
||||||
// /// In case of a broken symbolic link this will also return true.
|
/// 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
|
/// If you cannot access the directory containing the file, e.g., because of a
|
||||||
// /// permission error, this will return false.
|
/// permission error, this will return false.
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// ```rust,no_run
|
/// ```rust,no_run
|
||||||
// /// # #[cfg(unix)] {
|
/// # #[cfg(unix)] {
|
||||||
// /// use std::path::Path;
|
/// use std::path::Path;
|
||||||
// /// use std::os::unix::fs::symlink;
|
/// use std::os::unix::fs::symlink;
|
||||||
// ///
|
///
|
||||||
// /// let link_path = Path::new("link");
|
/// let link_path = Path::new("link");
|
||||||
// /// symlink("/origin_does_not_exist/", link_path).unwrap();
|
/// symlink("/origin_does_not_exist/", link_path).unwrap();
|
||||||
// /// assert_eq!(link_path.is_symlink(), true);
|
/// assert_eq!(link_path.is_symlink(), true);
|
||||||
// /// assert_eq!(link_path.exists(), false);
|
/// assert_eq!(link_path.exists(), false);
|
||||||
// /// # }
|
/// # }
|
||||||
// /// ```
|
/// ```
|
||||||
// ///
|
///
|
||||||
// /// # See Also
|
/// # See Also
|
||||||
// ///
|
///
|
||||||
// /// This is a convenience function that coerces errors to false. If you want to
|
/// 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
|
/// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
|
||||||
// /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
|
/// [`fs::Metadata::is_symlink`] if it was [`Ok`].
|
||||||
// #[must_use]
|
#[must_use]
|
||||||
// #[stable(feature = "is_symlink", since = "1.58.0")]
|
#[stable(feature = "is_symlink", since = "1.58.0")]
|
||||||
// pub fn is_symlink(&self) -> bool {
|
pub fn is_symlink(&self) -> bool {
|
||||||
// fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
|
fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
|
||||||
// }
|
}
|
||||||
|
|
||||||
/// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
|
/// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
|
||||||
/// allocating.
|
/// allocating.
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ pub mod rust_2024 {
|
|||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::vec::Vec;
|
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
|
// Re-exported built-in macros and traits
|
||||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
@@ -150,12 +154,6 @@ pub mod rust_2024 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[panic_handler]
|
|
||||||
// fn panic(_panic_info: &core::panic::PanicInfo) -> ! {
|
|
||||||
// // TODO print
|
|
||||||
// loop {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `argc` and `argv` are passed by the kernel
|
/// `argc` and `argv` are passed by the kernel
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
@@ -166,16 +164,4 @@ pub mod rust_2024 {
|
|||||||
|
|
||||||
unsafe { main(argc, argv) }
|
unsafe { main(argc, argv) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "start"]
|
|
||||||
pub fn lang_start<T: crate::process::Termination + 'static>(
|
|
||||||
main: fn() -> T,
|
|
||||||
argc: isize,
|
|
||||||
argv: *const *const u8,
|
|
||||||
_sigpipe: u8,
|
|
||||||
) -> isize {
|
|
||||||
println!("{}", argc);
|
|
||||||
println!("{:?}", argv);
|
|
||||||
main().report().to_i32() as isize
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,6 +156,7 @@
|
|||||||
target_env = "sgx",
|
target_env = "sgx",
|
||||||
target_os = "xous",
|
target_os = "xous",
|
||||||
target_os = "trusty",
|
target_os = "trusty",
|
||||||
|
target_os = "hermit",
|
||||||
))
|
))
|
||||||
))]
|
))]
|
||||||
mod tests;
|
mod tests;
|
||||||
@@ -1380,6 +1381,7 @@ impl Output {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # #![allow(unused_features)]
|
||||||
/// #![feature(exit_status_error)]
|
/// #![feature(exit_status_error)]
|
||||||
/// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] {
|
/// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] {
|
||||||
/// use std::process::Command;
|
/// use std::process::Command;
|
||||||
@@ -1679,32 +1681,32 @@ impl From<ChildStderr> for Stdio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[stable(feature = "stdio_from", since = "1.20.0")]
|
#[stable(feature = "stdio_from", since = "1.20.0")]
|
||||||
// impl From<fs::File> for Stdio {
|
impl From<fs::File> for Stdio {
|
||||||
// /// Converts a [`File`](fs::File) into a [`Stdio`].
|
/// Converts a [`File`](fs::File) into a [`Stdio`].
|
||||||
// ///
|
///
|
||||||
// /// # Examples
|
/// # Examples
|
||||||
// ///
|
///
|
||||||
// /// `File` will be converted to `Stdio` using `Stdio::from` under the hood.
|
/// `File` will be converted to `Stdio` using `Stdio::from` under the hood.
|
||||||
// ///
|
///
|
||||||
// /// ```rust,no_run
|
/// ```rust,no_run
|
||||||
// /// use std::fs::File;
|
/// use std::fs::File;
|
||||||
// /// use std::process::Command;
|
/// use std::process::Command;
|
||||||
// ///
|
///
|
||||||
// /// // With the `foo.txt` file containing "Hello, world!"
|
/// // With the `foo.txt` file containing "Hello, world!"
|
||||||
// /// let file = File::open("foo.txt")?;
|
/// let file = File::open("foo.txt")?;
|
||||||
// ///
|
///
|
||||||
// /// let reverse = Command::new("rev")
|
/// let reverse = Command::new("rev")
|
||||||
// /// .stdin(file) // Implicit File conversion into a Stdio
|
/// .stdin(file) // Implicit File conversion into a Stdio
|
||||||
// /// .output()?;
|
/// .output()?;
|
||||||
// ///
|
///
|
||||||
// /// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
|
/// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
|
||||||
// /// # std::io::Result::Ok(())
|
/// # std::io::Result::Ok(())
|
||||||
// /// ```
|
/// ```
|
||||||
// fn from(file: fs::File) -> Stdio {
|
fn from(file: fs::File) -> Stdio {
|
||||||
// Stdio::from_inner(file.into_inner().into())
|
Stdio::from_inner(file.into_inner().into())
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[stable(feature = "stdio_from_stdio", since = "1.74.0")]
|
#[stable(feature = "stdio_from_stdio", since = "1.74.0")]
|
||||||
impl From<io::Stdout> for Stdio {
|
impl From<io::Stdout> for Stdio {
|
||||||
@@ -1959,6 +1961,7 @@ impl crate::sealed::Sealed for ExitStatusError {}
|
|||||||
pub struct ExitStatusError(imp::ExitStatusError);
|
pub struct ExitStatusError(imp::ExitStatusError);
|
||||||
|
|
||||||
#[unstable(feature = "exit_status_error", issue = "84908")]
|
#[unstable(feature = "exit_status_error", issue = "84908")]
|
||||||
|
#[doc(test(attr(allow(unused_features))))]
|
||||||
impl ExitStatusError {
|
impl ExitStatusError {
|
||||||
/// Reports the exit code, if applicable, from an `ExitStatusError`.
|
/// Reports the exit code, if applicable, from an `ExitStatusError`.
|
||||||
///
|
///
|
||||||
@@ -2545,7 +2548,7 @@ pub fn abort() -> ! {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "getpid", since = "1.26.0")]
|
#[stable(feature = "getpid", since = "1.26.0")]
|
||||||
pub fn id() -> u32 {
|
pub fn id() -> u32 {
|
||||||
todo!()
|
imp::getpid()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for implementing arbitrary return types in the `main` function.
|
/// A trait for implementing arbitrary return types in the `main` function.
|
||||||
|
|||||||
96
crates/std/src/random.rs
Normal file
96
crates/std/src/random.rs
Normal file
@@ -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<T>(dist: impl Distribution<T>) -> T {
|
||||||
|
dist.sample(&mut DefaultRandomSource)
|
||||||
|
}
|
||||||
@@ -1,8 +1,211 @@
|
|||||||
macro_rules! rtabort {
|
//! Runtime services
|
||||||
($($t:tt)*) => {{ loop {} }};
|
//!
|
||||||
}
|
//! The `rt` module provides a narrow set of runtime services,
|
||||||
macro_rules! rtprintpanic {
|
//! including the global heap (exported in `heap`) and unwinding and
|
||||||
($($t:tt)*) => {{}};
|
//! 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<T>(e: Box<dyn Any + Send>) -> 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 <https://github.com/rust-lang/rust/issues/97889>
|
||||||
|
// 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<T: crate::process::Termination + 'static>(
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,18 +14,19 @@ pub use core::sync::atomic;
|
|||||||
pub use once::Once;
|
pub use once::Once;
|
||||||
pub use once::OnceState;
|
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::LockResult;
|
||||||
pub use poison::Mutex;
|
pub use poison::Mutex;
|
||||||
pub use poison::MutexGuard;
|
pub use poison::MutexGuard;
|
||||||
pub use poison::PoisonError;
|
pub use poison::PoisonError;
|
||||||
|
pub use poison::RwLock;
|
||||||
pub use poison::TryLockError;
|
pub use poison::TryLockError;
|
||||||
pub use poison::TryLockResult;
|
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::ReentrantLock;
|
||||||
pub use reentrant_lock::ReentrantLockGuard;
|
pub use reentrant_lock::ReentrantLockGuard;
|
||||||
pub use alloc_crate::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
||||||
|
|||||||
@@ -105,15 +105,6 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
|
|||||||
LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) }
|
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<T, F> {
|
|
||||||
let once = Once::new();
|
|
||||||
once.call_once(|| {});
|
|
||||||
LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes this `LazyLock` returning the stored value.
|
/// Consumes this `LazyLock` returning the stored value.
|
||||||
///
|
///
|
||||||
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
|
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
|
||||||
@@ -404,6 +395,19 @@ impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
impl<T, F> From<T> for LazyLock<T, F> {
|
||||||
|
/// 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]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn panic_poisoned() -> ! {
|
fn panic_poisoned() -> ! {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use super::select::Selected;
|
|||||||
use super::waker::current_thread_id;
|
use super::waker::current_thread_id;
|
||||||
use crate::cell::Cell;
|
use crate::cell::Cell;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize, Ordering};
|
use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize, Ordering};
|
||||||
use crate::thread::{self, Thread};
|
use crate::thread::{self, Thread};
|
||||||
use crate::time::Instant;
|
use crate::time::Instant;
|
||||||
|
|||||||
@@ -84,6 +84,13 @@ impl Once {
|
|||||||
Once { inner: sys::Once::new() }
|
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
|
/// 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,
|
/// will be executed if this is the first time `call_once` has been called,
|
||||||
/// and otherwise the routine will *not* be invoked.
|
/// and otherwise the routine will *not* be invoked.
|
||||||
|
|||||||
39
crates/std/src/sys/helpers/mod.rs
Normal file
39
crates/std/src/sys/helpers/mod.rs
Normal file
@@ -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<T>(result: crate::io::Result<T>) -> crate::io::Result<()> {
|
||||||
|
match result {
|
||||||
|
Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()),
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
60
crates/std/src/sys/helpers/small_c_string.rs
Normal file
60
crates/std/src/sys/helpers/small_c_string.rs
Normal file
@@ -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<T>(path: &Path, f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> {
|
||||||
|
run_with_cstr(path.as_os_str().as_encoded_bytes(), f)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn run_with_cstr<T>(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> {
|
||||||
|
// 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<T>(
|
||||||
|
bytes: &[u8],
|
||||||
|
f: &dyn Fn(&CStr) -> io::Result<T>,
|
||||||
|
) -> io::Result<T> {
|
||||||
|
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<T>(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result<T>) -> io::Result<T> {
|
||||||
|
match CString::new(bytes) {
|
||||||
|
Ok(s) => f(&s),
|
||||||
|
Err(_) => Err(NUL_ERR),
|
||||||
|
}
|
||||||
|
}
|
||||||
73
crates/std/src/sys/helpers/tests.rs
Normal file
73
crates/std/src/sys/helpers/tests.rs
Normal file
@@ -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::<String>();
|
||||||
|
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::<String>();
|
||||||
|
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::<String>();
|
||||||
|
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::<String>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
59
crates/std/src/sys/helpers/wstr.rs
Normal file
59
crates/std/src/sys/helpers/wstr.rs
Normal file
@@ -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<u16>,
|
||||||
|
// ...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<Self> {
|
||||||
|
Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek(&self) -> Option<NonZero<u16>> {
|
||||||
|
// 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<P: FnMut(NonZero<u16>) -> 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<u16>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,8 @@ pub mod thread;
|
|||||||
pub mod thread_local;
|
pub mod thread_local;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub use pal::*;
|
pub use pal::*;
|
||||||
// pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod helpers;
|
||||||
|
|
||||||
/// A trait for viewing representations from std types.
|
/// A trait for viewing representations from std types.
|
||||||
#[cfg_attr(not(target_os = "linux"), allow(unused))]
|
#[cfg_attr(not(target_os = "linux"), allow(unused))]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::borrow::Cow;
|
|||||||
use crate::bstr::ByteStr;
|
use crate::bstr::ByteStr;
|
||||||
use alloc_crate::collections::TryReserveError;
|
use alloc_crate::collections::TryReserveError;
|
||||||
use crate::rc::Rc;
|
use crate::rc::Rc;
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||||
use crate::{fmt, mem, str};
|
use crate::{fmt, mem, str};
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,3 @@ pub fn temp_dir() -> PathBuf {
|
|||||||
pub fn home_dir() -> Option<PathBuf> {
|
pub fn home_dir() -> Option<PathBuf> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getpid() -> u32 {
|
|
||||||
panic!("no pids on this platform")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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! {
|
cfg_select! {
|
||||||
target_os = "windows" => {
|
target_os = "windows" => {
|
||||||
mod windows;
|
mod windows;
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ use crate::ffi::OsStr;
|
|||||||
use crate::path::{Path, PathBuf, Prefix};
|
use crate::path::{Path, PathBuf, Prefix};
|
||||||
use crate::{env, io};
|
use crate::{env, io};
|
||||||
|
|
||||||
#[inline]
|
path_separator_bytes!(b'/');
|
||||||
pub fn is_sep_byte(b: u8) -> bool {
|
|
||||||
b == b'/'
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
pub const fn is_verbatim_sep(b: u8) -> bool {
|
||||||
b == b'/'
|
is_sep_byte(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const HAS_PREFIXES: bool = false;
|
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.
|
/// Make a POSIX path absolute without changing its semantics.
|
||||||
pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
|
pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ cfg_select! {
|
|||||||
mod env;
|
mod env;
|
||||||
|
|
||||||
pub use env::CommandEnvs;
|
pub use env::CommandEnvs;
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
pub use imp::getppid;
|
||||||
pub use imp::{
|
pub use imp::{
|
||||||
ChildPipe, Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio,
|
ChildPipe, Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio,
|
||||||
read_output,
|
getpid, read_output,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::ffi::{OsStr, OsString};
|
|||||||
use crate::num::NonZero;
|
use crate::num::NonZero;
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
use crate::process::StdioPipes;
|
use crate::process::StdioPipes;
|
||||||
// use crate::sys::fs::File;
|
use crate::sys::fs::File;
|
||||||
use crate::sys::unsupported;
|
use crate::sys::unsupported;
|
||||||
use crate::{fmt, io};
|
use crate::{fmt, io};
|
||||||
|
|
||||||
@@ -30,8 +30,8 @@ pub enum Stdio {
|
|||||||
MakePipe,
|
MakePipe,
|
||||||
ParentStdout,
|
ParentStdout,
|
||||||
ParentStderr,
|
ParentStderr,
|
||||||
// #[allow(dead_code)] // This variant exists only for the Debug impl
|
#[allow(dead_code)] // This variant exists only for the Debug impl
|
||||||
// InheritFile(File),
|
InheritFile(File),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
@@ -124,20 +124,18 @@ impl From<io::Stderr> for Stdio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl From<File> for Stdio {
|
impl From<File> for Stdio {
|
||||||
// fn from(file: File) -> Stdio {
|
fn from(file: File) -> Stdio {
|
||||||
// Stdio::InheritFile(file)
|
Stdio::InheritFile(file)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Command {
|
impl fmt::Debug for Command {
|
||||||
// show all attributes
|
// show all attributes
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
let mut debug_command = f.debug_struct("Command");
|
let mut debug_command = f.debug_struct("Command");
|
||||||
debug_command
|
debug_command.field("program", &self.program).field("args", &self.args);
|
||||||
.field("program", &self.program)
|
|
||||||
.field("args", &self.args);
|
|
||||||
if !self.env.is_unchanged() {
|
if !self.env.is_unchanged() {
|
||||||
debug_command.field("env", &self.env);
|
debug_command.field("env", &self.env);
|
||||||
}
|
}
|
||||||
@@ -329,3 +327,7 @@ pub fn read_output(
|
|||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
match out.diverge() {}
|
match out.diverge() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getpid() -> u32 {
|
||||||
|
panic!("no pids on this platform")
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ cfg_select! {
|
|||||||
all(target_os = "windows", not(target_vendor="win7")),
|
all(target_os = "windows", not(target_vendor="win7")),
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "android",
|
target_os = "android",
|
||||||
all(target_arch = "wasm32", target_feature = "atomics"),
|
all(target_family = "wasm", target_feature = "atomics"),
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
target_os = "motor",
|
target_os = "motor",
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ impl Once {
|
|||||||
Once { state: Cell::new(State::Incomplete) }
|
Once { state: Cell::new(State::Incomplete) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn new_complete() -> Once {
|
||||||
|
Once { state: Cell::new(State::Complete) }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_completed(&self) -> bool {
|
pub fn is_completed(&self) -> bool {
|
||||||
self.state.get() == State::Complete
|
self.state.get() == State::Complete
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ cfg_select! {
|
|||||||
all(target_os = "windows", not(target_vendor = "win7")),
|
all(target_os = "windows", not(target_vendor = "win7")),
|
||||||
target_os = "linux",
|
target_os = "linux",
|
||||||
target_os = "android",
|
target_os = "android",
|
||||||
all(target_arch = "wasm32", target_feature = "atomics"),
|
all(target_family = "wasm", target_feature = "atomics"),
|
||||||
target_os = "freebsd",
|
target_os = "freebsd",
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
target_os = "dragonfly",
|
target_os = "dragonfly",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub use current::current_id;
|
|||||||
pub(crate) use current::current_or_unnamed;
|
pub(crate) use current::current_or_unnamed;
|
||||||
pub(crate) use current::current_os_id;
|
pub(crate) use current::current_os_id;
|
||||||
pub(crate) use current::with_current_name;
|
pub(crate) use current::with_current_name;
|
||||||
|
pub(crate) use current::drop_current;
|
||||||
pub use functions::sleep;
|
pub use functions::sleep;
|
||||||
pub use id::ThreadId;
|
pub use id::ThreadId;
|
||||||
pub(crate) use lifecycle::ThreadInit;
|
pub(crate) use lifecycle::ThreadInit;
|
||||||
|
|||||||
@@ -168,7 +168,11 @@ pub fn yield_now() {
|
|||||||
imp::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
|
/// A common use of this feature is to poison shared resources when writing
|
||||||
/// unsafe code, by checking `panicking` when the `drop` is called.
|
/// unsafe code, by checking `panicking` when the `drop` is called.
|
||||||
@@ -309,14 +313,14 @@ pub fn sleep(dur: Duration) {
|
|||||||
///
|
///
|
||||||
/// | Platform | System call |
|
/// | Platform | System call |
|
||||||
/// |-----------|----------------------------------------------------------------------|
|
/// |-----------|----------------------------------------------------------------------|
|
||||||
/// | Linux | [clock_nanosleep] (Monotonic clock) |
|
/// | Linux | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] |
|
/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Android | [clock_nanosleep] (Monotonic Clock)] |
|
/// | Android | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Solaris | [clock_nanosleep] (Monotonic Clock)] |
|
/// | Solaris | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Illumos | [clock_nanosleep] (Monotonic Clock)] |
|
/// | Illumos | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] |
|
/// | Dragonfly | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Hurd | [clock_nanosleep] (Monotonic Clock)] |
|
/// | Hurd | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] |
|
/// | Vxworks | [clock_nanosleep] (Monotonic Clock) |
|
||||||
/// | Apple | `mach_wait_until` |
|
/// | Apple | `mach_wait_until` |
|
||||||
/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself |
|
/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself |
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use super::{Result, spawnhook};
|
|||||||
use crate::cell::UnsafeCell;
|
use crate::cell::UnsafeCell;
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
use crate::mem::{ManuallyDrop, MaybeUninit};
|
use crate::mem::{ManuallyDrop, MaybeUninit};
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
|
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
|
||||||
use crate::sys::{AsInner, IntoInner, thread as imp};
|
use crate::sys::{AsInner, IntoInner, thread as imp};
|
||||||
use crate::{env, io, panic};
|
use crate::{env, io, panic};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use super::lifecycle::{JoinInner, spawn_unchecked};
|
|||||||
use super::thread::Thread;
|
use super::thread::Thread;
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
|
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::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering};
|
||||||
use crate::{fmt, io};
|
use crate::{fmt, io};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::thread::Thread;
|
use super::thread::Thread;
|
||||||
use crate::cell::Cell;
|
use crate::cell::Cell;
|
||||||
use crate::iter;
|
use crate::iter;
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
|
|
||||||
crate::thread_local! {
|
crate::thread_local! {
|
||||||
/// A thread local linked list of spawn hooks.
|
/// A thread local linked list of spawn hooks.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::alloc::System;
|
|||||||
use crate::ffi::CStr;
|
use crate::ffi::CStr;
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::pin::Pin;
|
use crate::pin::Pin;
|
||||||
use alloc_crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sys::sync::Parker;
|
use crate::sys::sync::Parker;
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user