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]
|
||||
resolver = "3"
|
||||
members = ["crates/bytes-struct","crates/io","crates/std", "crates/shared", "user/*"]
|
||||
members = ["crates/bytes-struct","crates/io", "crates/shared", "user/*"]
|
||||
exclude = ["crates/std/crates/backtrace-rs"]
|
||||
|
||||
[package]
|
||||
name = "kernel-rust"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![feature(iterator_try_collect, iter_order_by)]
|
||||
#![allow(unused_features)]
|
||||
#![cfg_attr(any(not(feature = "std"), target_arch = "riscv64"), no_std)]
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
@@ -4,7 +4,8 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
backtrace_rs = { package = "backtrace", version = "0.3", default-features = false }
|
||||
cfg-if = { version = "1.0" }
|
||||
rustc-demangle = { version = "0.1.27" }
|
||||
hashbrown = "0.16"
|
||||
os-std-macros = { path = "../os-std-macros" }
|
||||
shared = { path = "../shared", features = ["user"] }
|
||||
|
||||
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:
|
||||
@# Not copied : sys/mod.rs, io.rs, error.rs, thread.rs, sync.rs
|
||||
# @just cp_std "process.rs"
|
||||
# @just cp_std "fs.rs"
|
||||
# @just cp_std "collections/mod.rs"
|
||||
@just cp_std "alloc.rs"
|
||||
@just cp_std "ascii.rs"
|
||||
@just cp_std "backtrace.rs"
|
||||
@just cp_std "bstr.rs"
|
||||
@just cp_std "env.rs"
|
||||
@just cp_std "error.rs"
|
||||
@just cp_std "fs.rs"
|
||||
@just cp_std "keyword_docs.rs"
|
||||
@just cp_std "macros.rs"
|
||||
@just cp_std "panic.rs"
|
||||
@just cp_std "panicking.rs"
|
||||
@just cp_std "pat.rs"
|
||||
@just cp_std "path.rs"
|
||||
@just cp_std "process.rs"
|
||||
@just cp_std "random.rs"
|
||||
@just cp_std "rt.rs"
|
||||
# @just cp_std "tests_helpers.rs"
|
||||
@just cp_std "time.rs"
|
||||
|
||||
@just cp_std "os/mod.rs"
|
||||
@just cp_std "os/raw/mod.rs"
|
||||
@just cp_std "os/raw/tests.rs"
|
||||
@just cp_std "bstr.rs"
|
||||
@just cp_std "panicking.rs"
|
||||
@just cp_std "panic.rs"
|
||||
@just cp_std "collections/hash/map.rs"
|
||||
@just cp_std "collections/hash/set.rs"
|
||||
@just cp_std "collections/hash/mod.rs"
|
||||
@@ -114,6 +126,7 @@ setup-std:
|
||||
@just cp_std "sys/cmath.rs"
|
||||
@just cp_std "sys/process/mod.rs"
|
||||
@just cp_std "sys/process/env.rs"
|
||||
@just cp_std "sys/process/unsupported.rs"
|
||||
@just cp_std "sys/args/mod.rs"
|
||||
@just cp_std "sys/args/unsupported.rs"
|
||||
@just cp_std "sys/pal/mod.rs"
|
||||
@@ -162,7 +175,10 @@ setup-std:
|
||||
@just cp_std "sys/stdio/unsupported.rs"
|
||||
@just cp_std "sys/alloc/mod.rs"
|
||||
@just cp_std "sys/backtrace.rs"
|
||||
@just cp_std "alloc.rs"
|
||||
@just cp_std "sys/fs/mod.rs"
|
||||
@just cp_std "sys/fs/unsupported.rs"
|
||||
@just cp_std "sys/helpers/mod.rs"
|
||||
@just cp_std "sys/helpers/small_c_string.rs"
|
||||
@just cp_std "sys/helpers/tests.rs"
|
||||
@just cp_std "sys/helpers/wstr.rs"
|
||||
@# Copied but edited for the moment
|
||||
# @just cp_std "sys/process/unsupported.rs"
|
||||
# @just cp_std "path.rs"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
s|crate::collections::TryReserveError|alloc_crate::collections::TryReserveError|g
|
||||
s|crate::sync::Arc|alloc_crate::sync::Arc|g
|
||||
s|alloc::ffi|alloc_crate::ffi|g
|
||||
s|alloc::slice::Join|alloc_crate::slice::Join|g
|
||||
s|alloc::bstr|alloc_crate::bstr|g
|
||||
|
||||
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);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||
#[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")]
|
||||
pub const fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
|
||||
@@ -389,6 +390,7 @@ impl<K, V, S> HashMap<K, V, S> {
|
||||
/// map.insert(1, 2);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap<K, V, S> {
|
||||
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 `HashMap` to be useful, see its documentation for details.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self {
|
||||
HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) }
|
||||
@@ -430,6 +433,7 @@ impl<K, V, S, A: Allocator> HashMap<K, V, S, A> {
|
||||
/// the `HashMap` to be useful, see its documentation for details.
|
||||
///
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self {
|
||||
HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) }
|
||||
|
||||
@@ -229,6 +229,7 @@ impl<T, S> HashSet<T, S> {
|
||||
/// set.insert(2);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||
#[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")]
|
||||
pub const fn with_hasher(hasher: S) -> HashSet<T, S> {
|
||||
@@ -261,6 +262,7 @@ impl<T, S> HashSet<T, S> {
|
||||
/// set.insert(1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
|
||||
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 `HashSet` to be useful, see its documentation for details.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet<T, S, A> {
|
||||
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 `HashSet` to be useful, see its documentation for details.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet<T, S, A> {
|
||||
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] /
|
||||
/// [`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].
|
||||
///
|
||||
|
||||
@@ -1,4 +1,562 @@
|
||||
// todo retreive docs
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::error::Error;
|
||||
#[unstable(feature = "error_generic_member_access", issue = "99301")]
|
||||
pub use core::error::{Request, request_ref, request_value};
|
||||
|
||||
use crate::backtrace::Backtrace;
|
||||
use crate::fmt::{self, Write};
|
||||
|
||||
/// An error reporter that prints an error and its sources.
|
||||
///
|
||||
/// Report also exposes configuration options for formatting the error sources, either entirely on a
|
||||
/// single line, or in multi-line format with each source on a new line.
|
||||
///
|
||||
/// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the
|
||||
/// wrapped error be `Send`, `Sync`, or `'static`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::{Error, Report};
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperError {
|
||||
/// source: SuperErrorSideKick,
|
||||
/// }
|
||||
///
|
||||
/// impl fmt::Display for SuperError {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// write!(f, "SuperError is here!")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Error for SuperError {
|
||||
/// fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// Some(&self.source)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperErrorSideKick;
|
||||
///
|
||||
/// impl fmt::Display for SuperErrorSideKick {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// write!(f, "SuperErrorSideKick is here!")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Error for SuperErrorSideKick {}
|
||||
///
|
||||
/// fn get_super_error() -> Result<(), SuperError> {
|
||||
/// Err(SuperError { source: SuperErrorSideKick })
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// match get_super_error() {
|
||||
/// Err(e) => println!("Error: {}", Report::new(e)),
|
||||
/// _ => println!("No error"),
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!: SuperErrorSideKick is here!
|
||||
/// ```
|
||||
///
|
||||
/// ## Output consistency
|
||||
///
|
||||
/// Report prints the same output via `Display` and `Debug`, so it works well with
|
||||
/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {}
|
||||
/// # fn get_super_error() -> Result<(), SuperError> {
|
||||
/// # Err(SuperError { source: SuperErrorSideKick })
|
||||
/// # }
|
||||
///
|
||||
/// get_super_error().map_err(Report::new).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// thread 'main' panicked at src/error.rs:34:40:
|
||||
/// called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!
|
||||
/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
/// ```
|
||||
///
|
||||
/// ## Return from `main`
|
||||
///
|
||||
/// `Report` also implements `From` for all types that implement [`Error`]; this when combined with
|
||||
/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
|
||||
/// from `main`.
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperError {
|
||||
/// # source: SuperErrorSideKick,
|
||||
/// # }
|
||||
/// # impl fmt::Display for SuperError {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperError is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperError {
|
||||
/// # fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
/// # Some(&self.source)
|
||||
/// # }
|
||||
/// # }
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct SuperErrorSideKick;
|
||||
/// # impl fmt::Display for SuperErrorSideKick {
|
||||
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// # write!(f, "SuperErrorSideKick is here!")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Error for SuperErrorSideKick {}
|
||||
/// # fn get_super_error() -> Result<(), SuperError> {
|
||||
/// # Err(SuperError { source: SuperErrorSideKick })
|
||||
/// # }
|
||||
///
|
||||
/// fn main() -> Result<(), Report<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::rc::Rc;
|
||||
use crate::str::FromStr;
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::os_str::{Buf, Slice};
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::{cmp, fmt, slice};
|
||||
@@ -576,15 +576,21 @@ impl OsString {
|
||||
|
||||
/// Truncate the `OsString` to the specified length.
|
||||
///
|
||||
/// If `new_len` is greater than the string's current length, this has no
|
||||
/// effect.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `len` does not lie on a valid `OsStr` boundary
|
||||
/// (as described in [`OsStr::slice_encoded_bytes`]).
|
||||
#[inline]
|
||||
#[unstable(feature = "os_string_truncate", issue = "133262")]
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
self.as_os_str().inner.check_public_boundary(len);
|
||||
// SAFETY: The length was just checked to be at a valid boundary.
|
||||
unsafe { self.inner.truncate_unchecked(len) };
|
||||
if len <= self.len() {
|
||||
self.as_os_str().inner.check_public_boundary(len);
|
||||
// SAFETY: The length was just checked to be at a valid boundary.
|
||||
unsafe { self.inner.truncate_unchecked(len) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides plumbing to `Vec::extend_from_slice` without giving full
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
target_os = "wasi",
|
||||
target_env = "sgx",
|
||||
target_os = "xous",
|
||||
target_os = "survos",
|
||||
target_os = "trusty",
|
||||
))
|
||||
))]
|
||||
@@ -46,7 +45,7 @@ use crate::ffi::OsString;
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sealed::Sealed;
|
||||
use alloc::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp};
|
||||
use crate::time::SystemTime;
|
||||
use crate::{error, fmt};
|
||||
@@ -2681,7 +2680,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
|
||||
///
|
||||
/// This function will only ever return an error of kind `NotFound` if the given
|
||||
/// path does not exist. Note that the inverse is not true,
|
||||
/// ie. if a path does not exist, its removal may fail for a number of reasons,
|
||||
/// i.e. if a path does not exist, its removal may fail for a number of reasons,
|
||||
/// such as insufficient permissions.
|
||||
///
|
||||
/// # Examples
|
||||
@@ -3151,7 +3150,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
///
|
||||
/// This function will only ever return an error of kind `NotFound` if the given
|
||||
/// path does not exist. Note that the inverse is not true,
|
||||
/// ie. if a path does not exist, its removal may fail for a number of reasons,
|
||||
/// i.e. if a path does not exist, its removal may fail for a number of reasons,
|
||||
/// such as insufficient permissions.
|
||||
///
|
||||
/// # Examples
|
||||
|
||||
@@ -21,12 +21,14 @@ pub use core::io::{BorrowedBuf, BorrowedCursor};
|
||||
use core::slice::memchr;
|
||||
pub use cursor::Cursor;
|
||||
|
||||
pub use self::stdio::{
|
||||
Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout,
|
||||
};
|
||||
pub use self::copy::copy;
|
||||
pub use self::pipe::{PipeReader, PipeWriter};
|
||||
pub use stdio::try_set_output_capture;
|
||||
pub use self::stdio::cleanup;
|
||||
pub use self::stdio::{
|
||||
_print, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout,
|
||||
};
|
||||
pub(crate) use stdio::attempt_print_to_stderr;
|
||||
pub use stdio::try_set_output_capture;
|
||||
|
||||
use crate::fs::File;
|
||||
use io::IoBase;
|
||||
@@ -43,7 +45,7 @@ impl IoBase for Stdin {
|
||||
|
||||
impl io::Read for Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> core::result::Result<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(internal_features)]
|
||||
#![deny(fuzzy_provenance_casts)]
|
||||
#![allow(fuzzy_provenance_casts)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
#![warn(rustdoc::unescaped_backticks)]
|
||||
@@ -265,7 +266,7 @@ pub use alloc_crate::vec;
|
||||
pub use core::{
|
||||
assert, cfg, column, compile_error, concat, const_format_args, env, file, format_args,
|
||||
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
|
||||
stringify, trace_macros,
|
||||
stringify, trace_macros, unimplemented
|
||||
};
|
||||
|
||||
#[rustc_std_internal_symbol]
|
||||
@@ -276,7 +277,6 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn core::panic::PanicPayload) -
|
||||
pub mod ffi;
|
||||
pub mod hash;
|
||||
pub mod io;
|
||||
// pub mod fs;
|
||||
pub mod error;
|
||||
pub mod num;
|
||||
pub mod path;
|
||||
@@ -285,17 +285,25 @@ pub mod process;
|
||||
#[macro_use]
|
||||
pub mod rt;
|
||||
pub mod alloc;
|
||||
pub mod ascii;
|
||||
pub mod backtrace;
|
||||
pub mod bstr;
|
||||
pub mod collections;
|
||||
pub mod env;
|
||||
pub mod fs;
|
||||
pub mod keyword_docs;
|
||||
pub mod macros;
|
||||
pub mod os;
|
||||
pub mod panic;
|
||||
pub mod panicking;
|
||||
pub mod pat;
|
||||
pub mod sync;
|
||||
pub mod sys;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
pub use backtrace_rs;
|
||||
|
||||
#[path = "../crates/backtrace-rs/src/lib.rs"]
|
||||
mod backtrace_rs;
|
||||
|
||||
#[prelude_import]
|
||||
#[allow(unused_imports)]
|
||||
@@ -310,23 +318,23 @@ mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
pub use shared::fs;
|
||||
pub use shared::fs as other_fs;
|
||||
pub use shared::syscall;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
($($args:expr),*) => {
|
||||
$crate::syscall::write_string_temp(&format!($($args),*))
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! println {
|
||||
() => {
|
||||
$crate::print!("");
|
||||
// $crate::print!("\n\r");
|
||||
};
|
||||
($($args:expr),*) => {
|
||||
$crate::print!($($args),*);
|
||||
// $crate::println!();
|
||||
};
|
||||
}
|
||||
// #[macro_export]
|
||||
// macro_rules! print {
|
||||
// ($($args:expr),*) => {
|
||||
// $crate::syscall::write_string_temp(&format!($($args),*))
|
||||
// };
|
||||
// }
|
||||
// #[macro_export]
|
||||
// macro_rules! println {
|
||||
// () => {
|
||||
// $crate::print!("");
|
||||
// // $crate::print!("\n\r");
|
||||
// };
|
||||
// ($($args:expr),*) => {
|
||||
// $crate::print!($($args),*);
|
||||
// // $crate::println!();
|
||||
// };
|
||||
// }
|
||||
|
||||
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::rc::Rc;
|
||||
use crate::str::FromStr;
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix};
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::path::{HAS_PREFIXES, is_sep_byte, is_verbatim_sep, parse_prefix};
|
||||
use crate::{cmp, fmt, fs, io, sys};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -266,22 +266,33 @@ impl<'a> Prefix<'a> {
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn is_separator(c: char) -> bool {
|
||||
#[rustc_const_unstable(feature = "const_path_separators", issue = "153106")]
|
||||
pub const fn is_separator(c: char) -> bool {
|
||||
c.is_ascii() && is_sep_byte(c as u8)
|
||||
}
|
||||
|
||||
/// The primary separator of path components for the current platform.
|
||||
///
|
||||
/// For example, `/` on Unix and `\` on Windows.
|
||||
/// All path separators recognized on the current platform, represented as [`char`]s; for example,
|
||||
/// this is `&['/'][..]` on Unix and `&['\\', '/'][..]` on Windows. The [primary
|
||||
/// separator](MAIN_SEPARATOR) is always element 0 of the slice.
|
||||
#[unstable(feature = "const_path_separators", issue = "153106")]
|
||||
pub const SEPARATORS: &[char] = crate::sys::path::SEPARATORS;
|
||||
|
||||
/// All path separators recognized on the current platform, represented as [`&str`]s; for example,
|
||||
/// this is `&["/"][..]` on Unix and `&["\\", "/"][..]` on Windows. The [primary
|
||||
/// separator](MAIN_SEPARATOR_STR) is always element 0 of the slice.
|
||||
#[unstable(feature = "const_path_separators", issue = "153106")]
|
||||
pub const SEPARATORS_STR: &[&str] = crate::sys::path::SEPARATORS_STR;
|
||||
|
||||
/// The primary separator of path components for the current platform, represented as a [`char`];
|
||||
/// for example, this is `'/'` on Unix and `'\\'` on Windows.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "path_main_separator")]
|
||||
pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
|
||||
pub const MAIN_SEPARATOR: char = SEPARATORS[0];
|
||||
|
||||
/// The primary separator of path components for the current platform.
|
||||
///
|
||||
/// For example, `/` on Unix and `\` on Windows.
|
||||
/// The primary separator of path components for the current platform, represented as a [`&str`];
|
||||
/// for example, this is `"/"` on Unix and `"\\"` on Windows.
|
||||
#[stable(feature = "main_separator_str", since = "1.68.0")]
|
||||
pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
|
||||
pub const MAIN_SEPARATOR_STR: &str = SEPARATORS_STR[0];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Misc helpers
|
||||
@@ -562,7 +573,7 @@ impl<'a> Component<'a> {
|
||||
pub fn as_os_str(self) -> &'a OsStr {
|
||||
match self {
|
||||
Component::Prefix(p) => p.as_os_str(),
|
||||
Component::RootDir => OsStr::new(MAIN_SEP_STR),
|
||||
Component::RootDir => OsStr::new(MAIN_SEPARATOR_STR),
|
||||
Component::CurDir => OsStr::new("."),
|
||||
Component::ParentDir => OsStr::new(".."),
|
||||
Component::Normal(path) => path,
|
||||
@@ -1379,7 +1390,7 @@ impl PathBuf {
|
||||
|
||||
for c in buf {
|
||||
if need_sep && c != Component::RootDir {
|
||||
res.push(MAIN_SEP_STR);
|
||||
res.push(MAIN_SEPARATOR_STR);
|
||||
}
|
||||
res.push(c.as_os_str());
|
||||
|
||||
@@ -1402,7 +1413,7 @@ impl PathBuf {
|
||||
|
||||
// `path` is a pure relative path
|
||||
} else if need_sep {
|
||||
self.inner.push(MAIN_SEP_STR);
|
||||
self.inner.push(MAIN_SEPARATOR_STR);
|
||||
}
|
||||
|
||||
self.inner.push(path);
|
||||
@@ -3240,73 +3251,101 @@ impl Path {
|
||||
self
|
||||
}
|
||||
|
||||
// /// Queries the file system to get information about a file, directory, etc.
|
||||
// ///
|
||||
// /// This function will traverse symbolic links to query information about the
|
||||
// /// destination file.
|
||||
// ///
|
||||
// /// This is an alias to [`fs::metadata`].
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// ///
|
||||
// /// let path = Path::new("/Minas/tirith");
|
||||
// /// let metadata = path.metadata().expect("metadata call failed");
|
||||
// /// println!("{:?}", metadata.file_type());
|
||||
// /// ```
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[inline]
|
||||
// pub fn metadata(&self) -> io::Result<fs::Metadata> {
|
||||
// fs::metadata(self)
|
||||
// }
|
||||
/// Queries the file system to get information about a file, directory, etc.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file.
|
||||
///
|
||||
/// This is an alias to [`fs::metadata`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let path = Path::new("/Minas/tirith");
|
||||
/// let metadata = path.metadata().expect("metadata call failed");
|
||||
/// println!("{:?}", metadata.file_type());
|
||||
/// ```
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn metadata(&self) -> io::Result<fs::Metadata> {
|
||||
fs::metadata(self)
|
||||
}
|
||||
|
||||
// /// Queries the metadata about a file without following symlinks.
|
||||
// ///
|
||||
// /// This is an alias to [`fs::symlink_metadata`].
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// ///
|
||||
// /// let path = Path::new("/Minas/tirith");
|
||||
// /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
|
||||
// /// println!("{:?}", metadata.file_type());
|
||||
// /// ```
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[inline]
|
||||
// pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
|
||||
// fs::symlink_metadata(self)
|
||||
// }
|
||||
/// Queries the metadata about a file without following symlinks.
|
||||
///
|
||||
/// This is an alias to [`fs::symlink_metadata`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let path = Path::new("/Minas/tirith");
|
||||
/// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
|
||||
/// println!("{:?}", metadata.file_type());
|
||||
/// ```
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
|
||||
fs::symlink_metadata(self)
|
||||
}
|
||||
|
||||
// /// Returns the canonical, absolute form of the path with all intermediate
|
||||
// /// components normalized and symbolic links resolved.
|
||||
// ///
|
||||
// /// This is an alias to [`fs::canonicalize`].
|
||||
// ///
|
||||
// /// # Errors
|
||||
// ///
|
||||
// /// This method will return an error in the following situations, but is not
|
||||
// /// limited to just these cases:
|
||||
// ///
|
||||
// /// * `path` does not exist.
|
||||
// /// * A non-final component in path is not a directory.
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::{Path, PathBuf};
|
||||
// ///
|
||||
// /// let path = Path::new("/foo/test/../test/bar.rs");
|
||||
// /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
|
||||
// /// ```
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[inline]
|
||||
// pub fn canonicalize(&self) -> io::Result<PathBuf> {
|
||||
// fs::canonicalize(self)
|
||||
// }
|
||||
/// Returns the canonical, absolute form of the path with all intermediate
|
||||
/// components normalized and symbolic links resolved.
|
||||
///
|
||||
/// This is an alias to [`fs::canonicalize`].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This method will return an error in the following situations, but is not
|
||||
/// limited to just these cases:
|
||||
///
|
||||
/// * `path` does not exist.
|
||||
/// * A non-final component in path is not a directory.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::{Path, PathBuf};
|
||||
///
|
||||
/// let path = Path::new("/foo/test/../test/bar.rs");
|
||||
/// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
|
||||
/// ```
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn canonicalize(&self) -> io::Result<PathBuf> {
|
||||
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.
|
||||
///
|
||||
@@ -3369,206 +3408,206 @@ impl Path {
|
||||
Ok(lexical)
|
||||
}
|
||||
|
||||
// /// Reads a symbolic link, returning the file that the link points to.
|
||||
// ///
|
||||
// /// This is an alias to [`fs::read_link`].
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// ///
|
||||
// /// let path = Path::new("/laputa/sky_castle.rs");
|
||||
// /// let path_link = path.read_link().expect("read_link call failed");
|
||||
// /// ```
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[inline]
|
||||
// pub fn read_link(&self) -> io::Result<PathBuf> {
|
||||
// fs::read_link(self)
|
||||
// }
|
||||
/// Reads a symbolic link, returning the file that the link points to.
|
||||
///
|
||||
/// This is an alias to [`fs::read_link`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let path = Path::new("/laputa/sky_castle.rs");
|
||||
/// let path_link = path.read_link().expect("read_link call failed");
|
||||
/// ```
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn read_link(&self) -> io::Result<PathBuf> {
|
||||
fs::read_link(self)
|
||||
}
|
||||
|
||||
// /// Returns an iterator over the entries within a directory.
|
||||
// ///
|
||||
// /// The iterator will yield instances of <code>[io::Result]<[fs::DirEntry]></code>. New
|
||||
// /// errors may be encountered after an iterator is initially constructed.
|
||||
// ///
|
||||
// /// This is an alias to [`fs::read_dir`].
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// ///
|
||||
// /// let path = Path::new("/laputa");
|
||||
// /// for entry in path.read_dir().expect("read_dir call failed") {
|
||||
// /// if let Ok(entry) = entry {
|
||||
// /// println!("{:?}", entry.path());
|
||||
// /// }
|
||||
// /// }
|
||||
// /// ```
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[inline]
|
||||
// pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
|
||||
// fs::read_dir(self)
|
||||
// }
|
||||
/// Returns an iterator over the entries within a directory.
|
||||
///
|
||||
/// The iterator will yield instances of <code>[io::Result]<[fs::DirEntry]></code>. New
|
||||
/// errors may be encountered after an iterator is initially constructed.
|
||||
///
|
||||
/// This is an alias to [`fs::read_dir`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let path = Path::new("/laputa");
|
||||
/// for entry in path.read_dir().expect("read_dir call failed") {
|
||||
/// if let Ok(entry) = entry {
|
||||
/// println!("{:?}", entry.path());
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[inline]
|
||||
pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
|
||||
fs::read_dir(self)
|
||||
}
|
||||
|
||||
// /// Returns `true` if the path points at an existing entity.
|
||||
// ///
|
||||
// /// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
|
||||
// /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs.
|
||||
// ///
|
||||
// /// This function will traverse symbolic links to query information about the
|
||||
// /// destination file.
|
||||
// ///
|
||||
// /// If you cannot access the metadata of the file, e.g. because of a
|
||||
// /// permission error or broken symbolic links, this will return `false`.
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// /// assert!(!Path::new("does_not_exist.txt").exists());
|
||||
// /// ```
|
||||
// ///
|
||||
// /// # See Also
|
||||
// ///
|
||||
// /// This is a convenience function that coerces errors to false. If you want to
|
||||
// /// check errors, call [`Path::try_exists`].
|
||||
// ///
|
||||
// /// [`try_exists()`]: Self::try_exists
|
||||
// /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[must_use]
|
||||
// #[inline]
|
||||
// pub fn exists(&self) -> bool {
|
||||
// fs::metadata(self).is_ok()
|
||||
// }
|
||||
/// Returns `true` if the path points at an existing entity.
|
||||
///
|
||||
/// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
|
||||
/// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file.
|
||||
///
|
||||
/// If you cannot access the metadata of the file, e.g. because of a
|
||||
/// permission error or broken symbolic links, this will return `false`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
/// assert!(!Path::new("does_not_exist.txt").exists());
|
||||
/// ```
|
||||
///
|
||||
/// # See Also
|
||||
///
|
||||
/// This is a convenience function that coerces errors to false. If you want to
|
||||
/// check errors, call [`Path::try_exists`].
|
||||
///
|
||||
/// [`try_exists()`]: Self::try_exists
|
||||
/// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn exists(&self) -> bool {
|
||||
fs::metadata(self).is_ok()
|
||||
}
|
||||
|
||||
// /// Returns `Ok(true)` if the path points at an existing entity.
|
||||
// ///
|
||||
// /// This function will traverse symbolic links to query information about the
|
||||
// /// destination file. In case of broken symbolic links this will return `Ok(false)`.
|
||||
// ///
|
||||
// /// [`Path::exists()`] only checks whether or not a path was both found and readable. By
|
||||
// /// contrast, `try_exists` will return `Ok(true)` or `Ok(false)`, respectively, if the path
|
||||
// /// was _verified_ to exist or not exist. If its existence can neither be confirmed nor
|
||||
// /// denied, it will propagate an `Err(_)` instead. This can be the case if e.g. listing
|
||||
// /// permission is denied on one of the parent directories.
|
||||
// ///
|
||||
// /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
||||
// /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
|
||||
// /// where those bugs are not an issue.
|
||||
// ///
|
||||
// /// This is an alias for [`std::fs::exists`](crate::fs::exists).
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
|
||||
// /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
|
||||
// /// ```
|
||||
// ///
|
||||
// /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||
// /// [`exists()`]: Self::exists
|
||||
// #[stable(feature = "path_try_exists", since = "1.63.0")]
|
||||
// #[inline]
|
||||
// pub fn try_exists(&self) -> io::Result<bool> {
|
||||
// fs::exists(self)
|
||||
// }
|
||||
/// Returns `Ok(true)` if the path points at an existing entity.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file. In case of broken symbolic links this will return `Ok(false)`.
|
||||
///
|
||||
/// [`Path::exists()`] only checks whether or not a path was both found and readable. By
|
||||
/// contrast, `try_exists` will return `Ok(true)` or `Ok(false)`, respectively, if the path
|
||||
/// was _verified_ to exist or not exist. If its existence can neither be confirmed nor
|
||||
/// denied, it will propagate an `Err(_)` instead. This can be the case if e.g. listing
|
||||
/// permission is denied on one of the parent directories.
|
||||
///
|
||||
/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
||||
/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
|
||||
/// where those bugs are not an issue.
|
||||
///
|
||||
/// This is an alias for [`std::fs::exists`](crate::fs::exists).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
/// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
|
||||
/// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
|
||||
/// ```
|
||||
///
|
||||
/// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||
/// [`exists()`]: Self::exists
|
||||
#[stable(feature = "path_try_exists", since = "1.63.0")]
|
||||
#[inline]
|
||||
pub fn try_exists(&self) -> io::Result<bool> {
|
||||
fs::exists(self)
|
||||
}
|
||||
|
||||
// /// Returns `true` if the path exists on disk and is pointing at a regular file.
|
||||
// ///
|
||||
// /// This function will traverse symbolic links to query information about the
|
||||
// /// destination file.
|
||||
// ///
|
||||
// /// If you cannot access the metadata of the file, e.g. because of a
|
||||
// /// permission error or broken symbolic links, this will return `false`.
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// /// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
|
||||
// /// assert_eq!(Path::new("a_file.txt").is_file(), true);
|
||||
// /// ```
|
||||
// ///
|
||||
// /// # See Also
|
||||
// ///
|
||||
// /// This is a convenience function that coerces errors to false. If you want to
|
||||
// /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
|
||||
// /// [`fs::Metadata::is_file`] if it was [`Ok`].
|
||||
// ///
|
||||
// /// When the goal is simply to read from (or write to) the source, the most
|
||||
// /// reliable way to test the source can be read (or written to) is to open
|
||||
// /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
|
||||
// /// a Unix-like system for example. See [`fs::File::open`] or
|
||||
// /// [`fs::OpenOptions::open`] for more information.
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[must_use]
|
||||
// pub fn is_file(&self) -> bool {
|
||||
// fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
|
||||
// }
|
||||
/// Returns `true` if the path exists on disk and is pointing at a regular file.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file.
|
||||
///
|
||||
/// If you cannot access the metadata of the file, e.g. because of a
|
||||
/// permission error or broken symbolic links, this will return `false`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
/// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
|
||||
/// assert_eq!(Path::new("a_file.txt").is_file(), true);
|
||||
/// ```
|
||||
///
|
||||
/// # See Also
|
||||
///
|
||||
/// This is a convenience function that coerces errors to false. If you want to
|
||||
/// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
|
||||
/// [`fs::Metadata::is_file`] if it was [`Ok`].
|
||||
///
|
||||
/// When the goal is simply to read from (or write to) the source, the most
|
||||
/// reliable way to test the source can be read (or written to) is to open
|
||||
/// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
|
||||
/// a Unix-like system for example. See [`fs::File::open`] or
|
||||
/// [`fs::OpenOptions::open`] for more information.
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[must_use]
|
||||
pub fn is_file(&self) -> bool {
|
||||
fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
|
||||
}
|
||||
|
||||
// /// Returns `true` if the path exists on disk and is pointing at a directory.
|
||||
// ///
|
||||
// /// This function will traverse symbolic links to query information about the
|
||||
// /// destination file.
|
||||
// ///
|
||||
// /// If you cannot access the metadata of the file, e.g. because of a
|
||||
// /// permission error or broken symbolic links, this will return `false`.
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```no_run
|
||||
// /// use std::path::Path;
|
||||
// /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
|
||||
// /// assert_eq!(Path::new("a_file.txt").is_dir(), false);
|
||||
// /// ```
|
||||
// ///
|
||||
// /// # See Also
|
||||
// ///
|
||||
// /// This is a convenience function that coerces errors to false. If you want to
|
||||
// /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
|
||||
// /// [`fs::Metadata::is_dir`] if it was [`Ok`].
|
||||
// #[stable(feature = "path_ext", since = "1.5.0")]
|
||||
// #[must_use]
|
||||
// pub fn is_dir(&self) -> bool {
|
||||
// fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
|
||||
// }
|
||||
/// Returns `true` if the path exists on disk and is pointing at a directory.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file.
|
||||
///
|
||||
/// If you cannot access the metadata of the file, e.g. because of a
|
||||
/// permission error or broken symbolic links, this will return `false`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::path::Path;
|
||||
/// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
|
||||
/// assert_eq!(Path::new("a_file.txt").is_dir(), false);
|
||||
/// ```
|
||||
///
|
||||
/// # See Also
|
||||
///
|
||||
/// This is a convenience function that coerces errors to false. If you want to
|
||||
/// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
|
||||
/// [`fs::Metadata::is_dir`] if it was [`Ok`].
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[must_use]
|
||||
pub fn is_dir(&self) -> bool {
|
||||
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
|
||||
}
|
||||
|
||||
// /// Returns `true` if the path exists on disk and is pointing at a symbolic link.
|
||||
// ///
|
||||
// /// This function will not traverse symbolic links.
|
||||
// /// In case of a broken symbolic link this will also return true.
|
||||
// ///
|
||||
// /// If you cannot access the directory containing the file, e.g., because of a
|
||||
// /// permission error, this will return false.
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// # #[cfg(unix)] {
|
||||
// /// use std::path::Path;
|
||||
// /// use std::os::unix::fs::symlink;
|
||||
// ///
|
||||
// /// let link_path = Path::new("link");
|
||||
// /// symlink("/origin_does_not_exist/", link_path).unwrap();
|
||||
// /// assert_eq!(link_path.is_symlink(), true);
|
||||
// /// assert_eq!(link_path.exists(), false);
|
||||
// /// # }
|
||||
// /// ```
|
||||
// ///
|
||||
// /// # See Also
|
||||
// ///
|
||||
// /// This is a convenience function that coerces errors to false. If you want to
|
||||
// /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
|
||||
// /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
|
||||
// #[must_use]
|
||||
// #[stable(feature = "is_symlink", since = "1.58.0")]
|
||||
// pub fn is_symlink(&self) -> bool {
|
||||
// fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
|
||||
// }
|
||||
/// Returns `true` if the path exists on disk and is pointing at a symbolic link.
|
||||
///
|
||||
/// This function will not traverse symbolic links.
|
||||
/// In case of a broken symbolic link this will also return true.
|
||||
///
|
||||
/// If you cannot access the directory containing the file, e.g., because of a
|
||||
/// permission error, this will return false.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # #[cfg(unix)] {
|
||||
/// use std::path::Path;
|
||||
/// use std::os::unix::fs::symlink;
|
||||
///
|
||||
/// let link_path = Path::new("link");
|
||||
/// symlink("/origin_does_not_exist/", link_path).unwrap();
|
||||
/// assert_eq!(link_path.is_symlink(), true);
|
||||
/// assert_eq!(link_path.exists(), false);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # See Also
|
||||
///
|
||||
/// This is a convenience function that coerces errors to false. If you want to
|
||||
/// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
|
||||
/// [`fs::Metadata::is_symlink`] if it was [`Ok`].
|
||||
#[must_use]
|
||||
#[stable(feature = "is_symlink", since = "1.58.0")]
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
|
||||
/// allocating.
|
||||
|
||||
@@ -17,6 +17,10 @@ pub mod rust_2024 {
|
||||
#[doc(no_inline)]
|
||||
pub use crate::vec::Vec;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::option::Option::{self, None, Some};
|
||||
|
||||
// Re-exported built-in macros and traits
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
#[doc(no_inline)]
|
||||
@@ -150,12 +154,6 @@ pub mod rust_2024 {
|
||||
}
|
||||
}
|
||||
|
||||
// #[panic_handler]
|
||||
// fn panic(_panic_info: &core::panic::PanicInfo) -> ! {
|
||||
// // TODO print
|
||||
// loop {}
|
||||
// }
|
||||
|
||||
/// # Safety
|
||||
/// `argc` and `argv` are passed by the kernel
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -166,16 +164,4 @@ pub mod rust_2024 {
|
||||
|
||||
unsafe { main(argc, argv) }
|
||||
}
|
||||
|
||||
#[lang = "start"]
|
||||
pub fn lang_start<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_os = "xous",
|
||||
target_os = "trusty",
|
||||
target_os = "hermit",
|
||||
))
|
||||
))]
|
||||
mod tests;
|
||||
@@ -1380,6 +1381,7 @@ impl Output {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(unused_features)]
|
||||
/// #![feature(exit_status_error)]
|
||||
/// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] {
|
||||
/// use std::process::Command;
|
||||
@@ -1679,32 +1681,32 @@ impl From<ChildStderr> for Stdio {
|
||||
}
|
||||
}
|
||||
|
||||
// #[stable(feature = "stdio_from", since = "1.20.0")]
|
||||
// impl From<fs::File> for Stdio {
|
||||
// /// Converts a [`File`](fs::File) into a [`Stdio`].
|
||||
// ///
|
||||
// /// # Examples
|
||||
// ///
|
||||
// /// `File` will be converted to `Stdio` using `Stdio::from` under the hood.
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use std::fs::File;
|
||||
// /// use std::process::Command;
|
||||
// ///
|
||||
// /// // With the `foo.txt` file containing "Hello, world!"
|
||||
// /// let file = File::open("foo.txt")?;
|
||||
// ///
|
||||
// /// let reverse = Command::new("rev")
|
||||
// /// .stdin(file) // Implicit File conversion into a Stdio
|
||||
// /// .output()?;
|
||||
// ///
|
||||
// /// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
|
||||
// /// # std::io::Result::Ok(())
|
||||
// /// ```
|
||||
// fn from(file: fs::File) -> Stdio {
|
||||
// Stdio::from_inner(file.into_inner().into())
|
||||
// }
|
||||
// }
|
||||
#[stable(feature = "stdio_from", since = "1.20.0")]
|
||||
impl From<fs::File> for Stdio {
|
||||
/// Converts a [`File`](fs::File) into a [`Stdio`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// `File` will be converted to `Stdio` using `Stdio::from` under the hood.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// // With the `foo.txt` file containing "Hello, world!"
|
||||
/// let file = File::open("foo.txt")?;
|
||||
///
|
||||
/// let reverse = Command::new("rev")
|
||||
/// .stdin(file) // Implicit File conversion into a Stdio
|
||||
/// .output()?;
|
||||
///
|
||||
/// assert_eq!(reverse.stdout, b"!dlrow ,olleH");
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
fn from(file: fs::File) -> Stdio {
|
||||
Stdio::from_inner(file.into_inner().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "stdio_from_stdio", since = "1.74.0")]
|
||||
impl From<io::Stdout> for Stdio {
|
||||
@@ -1959,6 +1961,7 @@ impl crate::sealed::Sealed for ExitStatusError {}
|
||||
pub struct ExitStatusError(imp::ExitStatusError);
|
||||
|
||||
#[unstable(feature = "exit_status_error", issue = "84908")]
|
||||
#[doc(test(attr(allow(unused_features))))]
|
||||
impl ExitStatusError {
|
||||
/// Reports the exit code, if applicable, from an `ExitStatusError`.
|
||||
///
|
||||
@@ -2545,7 +2548,7 @@ pub fn abort() -> ! {
|
||||
#[must_use]
|
||||
#[stable(feature = "getpid", since = "1.26.0")]
|
||||
pub fn id() -> u32 {
|
||||
todo!()
|
||||
imp::getpid()
|
||||
}
|
||||
|
||||
/// A trait for implementing arbitrary return types in the `main` function.
|
||||
|
||||
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 {
|
||||
($($t:tt)*) => {{ loop {} }};
|
||||
}
|
||||
macro_rules! rtprintpanic {
|
||||
($($t:tt)*) => {{}};
|
||||
//! Runtime services
|
||||
//!
|
||||
//! The `rt` module provides a narrow set of runtime services,
|
||||
//! including the global heap (exported in `heap`) and unwinding and
|
||||
//! backtrace support. The APIs in this module are highly unstable,
|
||||
//! and should be considered as private implementation details for the
|
||||
//! time being.
|
||||
|
||||
#![unstable(
|
||||
feature = "rt",
|
||||
reason = "this public module should not exist and is highly likely \
|
||||
to disappear",
|
||||
issue = "none"
|
||||
)]
|
||||
#![doc(hidden)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(unused_macros)]
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub use crate::panicking::{begin_panic, panic_count};
|
||||
pub use core::panicking::{panic_display, panic_fmt};
|
||||
|
||||
#[rustfmt::skip]
|
||||
use crate::any::Any;
|
||||
use crate::sync::Once;
|
||||
use crate::thread::{self, main_thread};
|
||||
use crate::{mem, panic, sys};
|
||||
|
||||
// This function is needed by the panic runtime.
|
||||
#[cfg(not(test))]
|
||||
#[rustc_std_internal_symbol]
|
||||
fn __rust_abort() {
|
||||
crate::process::abort();
|
||||
}
|
||||
|
||||
pub fn cleanup() {}
|
||||
// Prints to the "panic output", depending on the platform this may be:
|
||||
// - the standard error output
|
||||
// - some dedicated platform specific output
|
||||
// - nothing (so this macro is a no-op)
|
||||
macro_rules! rtprintpanic {
|
||||
($($t:tt)*) => {
|
||||
#[cfg(not(panic = "immediate-abort"))]
|
||||
if let Some(mut out) = crate::sys::stdio::panic_output() {
|
||||
let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
|
||||
}
|
||||
#[cfg(panic = "immediate-abort")]
|
||||
{
|
||||
let _ = format_args!($($t)*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! rtabort {
|
||||
($($t:tt)*) => {
|
||||
{
|
||||
rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*));
|
||||
crate::process::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! rtassert {
|
||||
($e:expr) => {
|
||||
if !$e {
|
||||
rtabort!(concat!("assertion failed: ", stringify!($e)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! rtunwrap {
|
||||
($ok:ident, $e:expr) => {
|
||||
match $e {
|
||||
$ok(v) => v,
|
||||
ref err => {
|
||||
let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
|
||||
rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn handle_rt_panic<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::OnceState;
|
||||
|
||||
pub use alloc_crate::sync::Arc;
|
||||
pub use lazy_lock::LazyLock;
|
||||
pub use once_lock::OnceLock;
|
||||
pub use poison::Condvar;
|
||||
pub use poison::LockResult;
|
||||
pub use poison::Mutex;
|
||||
pub use poison::MutexGuard;
|
||||
pub use poison::PoisonError;
|
||||
pub use poison::RwLock;
|
||||
pub use poison::TryLockError;
|
||||
pub use poison::TryLockResult;
|
||||
pub use poison::Condvar;
|
||||
pub use poison::RwLock;
|
||||
pub use once_lock::OnceLock;
|
||||
pub use reentrant_lock::ReentrantLock;
|
||||
pub use reentrant_lock::ReentrantLockGuard;
|
||||
pub use alloc_crate::sync::Arc;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[stable(feature = "wait_timeout", since = "1.5.0")]
|
||||
|
||||
@@ -105,15 +105,6 @@ impl<T, F: FnOnce() -> T> LazyLock<T, 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.
|
||||
///
|
||||
/// 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]
|
||||
#[inline(never)]
|
||||
fn panic_poisoned() -> ! {
|
||||
|
||||
@@ -4,7 +4,7 @@ use super::select::Selected;
|
||||
use super::waker::current_thread_id;
|
||||
use crate::cell::Cell;
|
||||
use crate::ptr;
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize, Ordering};
|
||||
use crate::thread::{self, Thread};
|
||||
use crate::time::Instant;
|
||||
|
||||
@@ -84,6 +84,13 @@ impl Once {
|
||||
Once { inner: sys::Once::new() }
|
||||
}
|
||||
|
||||
/// Creates a new `Once` value that starts already completed.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) const fn new_complete() -> Once {
|
||||
Once { inner: sys::Once::new_complete() }
|
||||
}
|
||||
|
||||
/// Performs an initialization routine once and only once. The given closure
|
||||
/// will be executed if this is the first time `call_once` has been called,
|
||||
/// and otherwise the routine will *not* be invoked.
|
||||
|
||||
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 time;
|
||||
pub use pal::*;
|
||||
// pub mod fs;
|
||||
pub mod fs;
|
||||
pub mod helpers;
|
||||
|
||||
/// A trait for viewing representations from std types.
|
||||
#[cfg_attr(not(target_os = "linux"), allow(unused))]
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::borrow::Cow;
|
||||
use crate::bstr::ByteStr;
|
||||
use alloc_crate::collections::TryReserveError;
|
||||
use crate::rc::Rc;
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::{fmt, mem, str};
|
||||
|
||||
|
||||
@@ -55,7 +55,3 @@ pub fn temp_dir() -> PathBuf {
|
||||
pub fn home_dir() -> Option<PathBuf> {
|
||||
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! {
|
||||
target_os = "windows" => {
|
||||
mod windows;
|
||||
|
||||
@@ -2,14 +2,11 @@ use crate::ffi::OsStr;
|
||||
use crate::path::{Path, PathBuf, Prefix};
|
||||
use crate::{env, io};
|
||||
|
||||
#[inline]
|
||||
pub fn is_sep_byte(b: u8) -> bool {
|
||||
b == b'/'
|
||||
}
|
||||
path_separator_bytes!(b'/');
|
||||
|
||||
#[inline]
|
||||
pub fn is_verbatim_sep(b: u8) -> bool {
|
||||
b == b'/'
|
||||
pub const fn is_verbatim_sep(b: u8) -> bool {
|
||||
is_sep_byte(b)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
|
||||
}
|
||||
|
||||
pub const HAS_PREFIXES: bool = false;
|
||||
pub const MAIN_SEP_STR: &str = "/";
|
||||
pub const MAIN_SEP: char = '/';
|
||||
|
||||
/// Make a POSIX path absolute without changing its semantics.
|
||||
pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
|
||||
|
||||
@@ -27,9 +27,11 @@ cfg_select! {
|
||||
mod env;
|
||||
|
||||
pub use env::CommandEnvs;
|
||||
#[cfg(target_family = "unix")]
|
||||
pub use imp::getppid;
|
||||
pub use imp::{
|
||||
ChildPipe, Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio,
|
||||
read_output,
|
||||
getpid, read_output,
|
||||
};
|
||||
|
||||
#[cfg(any(
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::ffi::{OsStr, OsString};
|
||||
use crate::num::NonZero;
|
||||
use crate::path::Path;
|
||||
use crate::process::StdioPipes;
|
||||
// use crate::sys::fs::File;
|
||||
use crate::sys::fs::File;
|
||||
use crate::sys::unsupported;
|
||||
use crate::{fmt, io};
|
||||
|
||||
@@ -30,8 +30,8 @@ pub enum Stdio {
|
||||
MakePipe,
|
||||
ParentStdout,
|
||||
ParentStderr,
|
||||
// #[allow(dead_code)] // This variant exists only for the Debug impl
|
||||
// InheritFile(File),
|
||||
#[allow(dead_code)] // This variant exists only for the Debug impl
|
||||
InheritFile(File),
|
||||
}
|
||||
|
||||
impl Command {
|
||||
@@ -124,20 +124,18 @@ impl From<io::Stderr> for Stdio {
|
||||
}
|
||||
}
|
||||
|
||||
// impl From<File> for Stdio {
|
||||
// fn from(file: File) -> Stdio {
|
||||
// Stdio::InheritFile(file)
|
||||
// }
|
||||
// }
|
||||
impl From<File> for Stdio {
|
||||
fn from(file: File) -> Stdio {
|
||||
Stdio::InheritFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Command {
|
||||
// show all attributes
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if f.alternate() {
|
||||
let mut debug_command = f.debug_struct("Command");
|
||||
debug_command
|
||||
.field("program", &self.program)
|
||||
.field("args", &self.args);
|
||||
debug_command.field("program", &self.program).field("args", &self.args);
|
||||
if !self.env.is_unchanged() {
|
||||
debug_command.field("env", &self.env);
|
||||
}
|
||||
@@ -329,3 +327,7 @@ pub fn read_output(
|
||||
) -> io::Result<()> {
|
||||
match out.diverge() {}
|
||||
}
|
||||
|
||||
pub fn getpid() -> u32 {
|
||||
panic!("no pids on this platform")
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ cfg_select! {
|
||||
all(target_os = "windows", not(target_vendor="win7")),
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
all(target_arch = "wasm32", target_feature = "atomics"),
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "freebsd",
|
||||
target_os = "motor",
|
||||
target_os = "openbsd",
|
||||
|
||||
@@ -39,6 +39,11 @@ impl Once {
|
||||
Once { state: Cell::new(State::Incomplete) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn new_complete() -> Once {
|
||||
Once { state: Cell::new(State::Complete) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_completed(&self) -> bool {
|
||||
self.state.get() == State::Complete
|
||||
|
||||
@@ -3,7 +3,7 @@ cfg_select! {
|
||||
all(target_os = "windows", not(target_vendor = "win7")),
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
all(target_arch = "wasm32", target_feature = "atomics"),
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
|
||||
@@ -17,6 +17,7 @@ pub use current::current_id;
|
||||
pub(crate) use current::current_or_unnamed;
|
||||
pub(crate) use current::current_os_id;
|
||||
pub(crate) use current::with_current_name;
|
||||
pub(crate) use current::drop_current;
|
||||
pub use functions::sleep;
|
||||
pub use id::ThreadId;
|
||||
pub(crate) use lifecycle::ThreadInit;
|
||||
|
||||
@@ -168,7 +168,11 @@ pub fn yield_now() {
|
||||
imp::yield_now()
|
||||
}
|
||||
|
||||
/// Determines whether the current thread is unwinding because of panic.
|
||||
/// Determines whether the current thread is panicking.
|
||||
///
|
||||
/// This returns `true` both when the thread is unwinding due to a panic,
|
||||
/// or executing a panic hook. Note that the latter case will still happen
|
||||
/// when `panic=abort` is set.
|
||||
///
|
||||
/// A common use of this feature is to poison shared resources when writing
|
||||
/// unsafe code, by checking `panicking` when the `drop` is called.
|
||||
@@ -309,14 +313,14 @@ pub fn sleep(dur: Duration) {
|
||||
///
|
||||
/// | Platform | System call |
|
||||
/// |-----------|----------------------------------------------------------------------|
|
||||
/// | Linux | [clock_nanosleep] (Monotonic clock) |
|
||||
/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Android | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Solaris | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Illumos | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Hurd | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] |
|
||||
/// | Linux | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Android | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Solaris | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Illumos | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Dragonfly | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Hurd | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Vxworks | [clock_nanosleep] (Monotonic Clock) |
|
||||
/// | Apple | `mach_wait_until` |
|
||||
/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself |
|
||||
///
|
||||
|
||||
@@ -8,7 +8,7 @@ use super::{Result, spawnhook};
|
||||
use crate::cell::UnsafeCell;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::{ManuallyDrop, MaybeUninit};
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
|
||||
use crate::sys::{AsInner, IntoInner, thread as imp};
|
||||
use crate::{env, io, panic};
|
||||
|
||||
@@ -5,7 +5,7 @@ use super::lifecycle::{JoinInner, spawn_unchecked};
|
||||
use super::thread::Thread;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering};
|
||||
use crate::{fmt, io};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::thread::Thread;
|
||||
use crate::cell::Cell;
|
||||
use crate::iter;
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
|
||||
crate::thread_local! {
|
||||
/// A thread local linked list of spawn hooks.
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::alloc::System;
|
||||
use crate::ffi::CStr;
|
||||
use crate::fmt;
|
||||
use crate::pin::Pin;
|
||||
use alloc_crate::sync::Arc;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::sync::Parker;
|
||||
use crate::time::Duration;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user