From a134536d2ffe914701efce42d487824a4bb3627d Mon Sep 17 00:00:00 2001 From: Julien THILLARD Date: Fri, 20 Mar 2026 10:30:23 +0100 Subject: [PATCH] Add more from the std --- library/.gitignore | 2 + library/justfile | 201 +- library/std/.gitignore | 107 + library/std/build.rs | 109 +- library/std/src/alloc.rs | 491 +- library/std/src/ascii.rs | 211 +- library/std/src/backtrace.rs | 479 +- library/std/src/bstr.rs | 5 +- library/std/src/env.rs | 1169 +---- library/std/src/error.rs | 563 +-- library/std/src/fs.rs | 3532 +------------- library/std/src/keyword_docs.rs | 2755 +---------- library/std/src/lib.rs | 767 +--- library/std/src/macros.rs | 417 +- library/std/src/os/mod.rs | 199 +- library/std/src/os/raw/mod.rs | 27 +- library/std/src/os/raw/tests.rs | 18 +- library/std/src/panic.rs | 535 +-- library/std/src/panicking.rs | 895 +--- library/std/src/pat.rs | 4 +- library/std/src/path.rs | 4087 +---------------- library/std/src/process.rs | 2623 +---------- library/std/src/random.rs | 97 +- library/std/src/rt.rs | 212 +- library/std/src/sys/args/unsupported.rs | 43 +- library/std/src/sys/backtrace.rs | 239 +- library/std/src/sys/cmath.rs | 115 +- library/std/src/sys/configure_builtins.rs | 63 +- library/std/src/sys/env/common.rs | 32 +- library/std/src/sys/env/mod.rs | 63 +- library/std/src/sys/env/unsupported.rs | 34 +- library/std/src/sys/env_consts.rs | 427 +- library/std/src/sys/exit.rs | 144 +- library/std/src/sys/fd/mod.rs | 24 +- library/std/src/sys/fs/common.rs | 82 +- library/std/src/sys/fs/mod.rs | 174 +- library/std/src/sys/fs/unsupported.rs | 363 +- library/std/src/sys/helpers/mod.rs | 40 +- library/std/src/sys/helpers/small_c_string.rs | 61 +- library/std/src/sys/helpers/tests.rs | 74 +- library/std/src/sys/helpers/wstr.rs | 60 +- library/std/src/sys/io/error/generic.rs | 16 +- .../std/src/sys/io/io_slice/unsupported.rs | 53 +- .../std/src/sys/io/is_terminal/unsupported.rs | 4 +- library/std/src/sys/io/kernel_copy/mod.rs | 24 +- library/std/src/sys/io/mod.rs | 73 +- library/std/src/sys/mod.rs | 56 +- library/std/src/sys/net/connection/mod.rs | 62 +- .../std/src/sys/net/connection/unsupported.rs | 317 +- library/std/src/sys/net/hostname/mod.rs | 16 +- .../std/src/sys/net/hostname/unsupported.rs | 7 +- library/std/src/sys/net/mod.rs | 8 +- library/std/src/sys/os_str/bytes.rs | 364 +- library/std/src/sys/os_str/bytes/tests.rs | 18 +- library/std/src/sys/os_str/mod.rs | 17 +- library/std/src/sys/pal/unsupported/common.rs | 22 +- library/std/src/sys/pal/unsupported/mod.rs | 7 +- library/std/src/sys/pal/unsupported/os.rs | 58 +- library/std/src/sys/path/mod.rs | 48 +- library/std/src/sys/path/unix.rs | 67 +- library/std/src/sys/personality/dwarf/eh.rs | 272 +- library/std/src/sys/personality/dwarf/mod.rs | 70 +- .../std/src/sys/personality/dwarf/tests.rs | 20 +- library/std/src/sys/personality/mod.rs | 51 +- library/std/src/sys/pipe/mod.rs | 21 +- library/std/src/sys/pipe/unsupported.rs | 102 +- library/std/src/sys/platform_version/mod.rs | 14 +- library/std/src/sys/process/env.rs | 116 +- library/std/src/sys/process/mod.rs | 89 +- library/std/src/sys/process/unsupported.rs | 334 +- library/std/src/sys/random/unsupported.rs | 16 +- library/std/src/sys/stdio/mod.rs | 53 +- library/std/src/sys/stdio/unsupported.rs | 107 +- library/std/src/sys/sync/condvar/mod.rs | 45 +- .../std/src/sys/sync/condvar/no_threads.rs | 28 +- library/std/src/sys/sync/mod.rs | 15 +- library/std/src/sys/sync/mutex/mod.rs | 48 +- library/std/src/sys/sync/mutex/no_threads.rs | 32 +- library/std/src/sys/sync/once/mod.rs | 41 +- library/std/src/sys/sync/once/no_threads.rs | 120 +- library/std/src/sys/sync/once_box.rs | 84 +- library/std/src/sys/sync/rwlock/mod.rs | 36 +- library/std/src/sys/sync/rwlock/no_threads.rs | 70 +- .../std/src/sys/sync/thread_parking/mod.rs | 50 +- .../sys/sync/thread_parking/unsupported.rs | 12 +- library/std/src/sys/thread/mod.rs | 155 +- library/std/src/sys/thread/unsupported.rs | 47 +- .../std/src/sys/thread_local/no_threads.rs | 151 +- library/std/src/sys/thread_local/os.rs | 290 +- library/std/src/sys/time/mod.rs | 54 +- library/std/src/sys/time/unsupported.rs | 50 +- library/std/src/time.rs | 860 +--- 92 files changed, 440 insertions(+), 25793 deletions(-) create mode 100644 library/std/.gitignore mode change 100644 => 120000 library/std/src/alloc.rs mode change 100644 => 120000 library/std/src/ascii.rs mode change 100644 => 120000 library/std/src/backtrace.rs mode change 100644 => 120000 library/std/src/bstr.rs mode change 100644 => 120000 library/std/src/env.rs mode change 100644 => 120000 library/std/src/error.rs mode change 100644 => 120000 library/std/src/fs.rs mode change 100644 => 120000 library/std/src/keyword_docs.rs mode change 100644 => 120000 library/std/src/lib.rs mode change 100644 => 120000 library/std/src/macros.rs mode change 100644 => 120000 library/std/src/os/mod.rs mode change 100644 => 120000 library/std/src/os/raw/mod.rs mode change 100644 => 120000 library/std/src/os/raw/tests.rs mode change 100644 => 120000 library/std/src/panic.rs mode change 100644 => 120000 library/std/src/panicking.rs mode change 100644 => 120000 library/std/src/pat.rs mode change 100644 => 120000 library/std/src/path.rs mode change 100644 => 120000 library/std/src/process.rs mode change 100644 => 120000 library/std/src/random.rs mode change 100644 => 120000 library/std/src/rt.rs mode change 100644 => 120000 library/std/src/sys/args/unsupported.rs mode change 100644 => 120000 library/std/src/sys/backtrace.rs mode change 100644 => 120000 library/std/src/sys/cmath.rs mode change 100644 => 120000 library/std/src/sys/configure_builtins.rs mode change 100644 => 120000 library/std/src/sys/env/common.rs mode change 100644 => 120000 library/std/src/sys/env/mod.rs mode change 100644 => 120000 library/std/src/sys/env/unsupported.rs mode change 100644 => 120000 library/std/src/sys/env_consts.rs mode change 100644 => 120000 library/std/src/sys/exit.rs mode change 100644 => 120000 library/std/src/sys/fd/mod.rs mode change 100644 => 120000 library/std/src/sys/fs/common.rs mode change 100644 => 120000 library/std/src/sys/fs/mod.rs mode change 100644 => 120000 library/std/src/sys/fs/unsupported.rs mode change 100644 => 120000 library/std/src/sys/helpers/mod.rs mode change 100644 => 120000 library/std/src/sys/helpers/small_c_string.rs mode change 100644 => 120000 library/std/src/sys/helpers/tests.rs mode change 100644 => 120000 library/std/src/sys/helpers/wstr.rs mode change 100644 => 120000 library/std/src/sys/io/error/generic.rs mode change 100644 => 120000 library/std/src/sys/io/io_slice/unsupported.rs mode change 100644 => 120000 library/std/src/sys/io/is_terminal/unsupported.rs mode change 100644 => 120000 library/std/src/sys/io/kernel_copy/mod.rs mode change 100644 => 120000 library/std/src/sys/io/mod.rs mode change 100644 => 120000 library/std/src/sys/mod.rs mode change 100644 => 120000 library/std/src/sys/net/connection/mod.rs mode change 100644 => 120000 library/std/src/sys/net/connection/unsupported.rs mode change 100644 => 120000 library/std/src/sys/net/hostname/mod.rs mode change 100644 => 120000 library/std/src/sys/net/hostname/unsupported.rs mode change 100644 => 120000 library/std/src/sys/net/mod.rs mode change 100644 => 120000 library/std/src/sys/os_str/bytes.rs mode change 100644 => 120000 library/std/src/sys/os_str/bytes/tests.rs mode change 100644 => 120000 library/std/src/sys/os_str/mod.rs mode change 100644 => 120000 library/std/src/sys/pal/unsupported/common.rs mode change 100644 => 120000 library/std/src/sys/pal/unsupported/mod.rs mode change 100644 => 120000 library/std/src/sys/pal/unsupported/os.rs mode change 100644 => 120000 library/std/src/sys/path/mod.rs mode change 100644 => 120000 library/std/src/sys/path/unix.rs mode change 100644 => 120000 library/std/src/sys/personality/dwarf/eh.rs mode change 100644 => 120000 library/std/src/sys/personality/dwarf/mod.rs mode change 100644 => 120000 library/std/src/sys/personality/dwarf/tests.rs mode change 100644 => 120000 library/std/src/sys/personality/mod.rs mode change 100644 => 120000 library/std/src/sys/pipe/mod.rs mode change 100644 => 120000 library/std/src/sys/pipe/unsupported.rs mode change 100644 => 120000 library/std/src/sys/platform_version/mod.rs mode change 100644 => 120000 library/std/src/sys/process/env.rs mode change 100644 => 120000 library/std/src/sys/process/mod.rs mode change 100644 => 120000 library/std/src/sys/process/unsupported.rs mode change 100644 => 120000 library/std/src/sys/random/unsupported.rs mode change 100644 => 120000 library/std/src/sys/stdio/mod.rs mode change 100644 => 120000 library/std/src/sys/stdio/unsupported.rs mode change 100644 => 120000 library/std/src/sys/sync/condvar/mod.rs mode change 100644 => 120000 library/std/src/sys/sync/condvar/no_threads.rs mode change 100644 => 120000 library/std/src/sys/sync/mod.rs mode change 100644 => 120000 library/std/src/sys/sync/mutex/mod.rs mode change 100644 => 120000 library/std/src/sys/sync/mutex/no_threads.rs mode change 100644 => 120000 library/std/src/sys/sync/once/mod.rs mode change 100644 => 120000 library/std/src/sys/sync/once/no_threads.rs mode change 100644 => 120000 library/std/src/sys/sync/once_box.rs mode change 100644 => 120000 library/std/src/sys/sync/rwlock/mod.rs mode change 100644 => 120000 library/std/src/sys/sync/rwlock/no_threads.rs mode change 100644 => 120000 library/std/src/sys/sync/thread_parking/mod.rs mode change 100644 => 120000 library/std/src/sys/sync/thread_parking/unsupported.rs mode change 100644 => 120000 library/std/src/sys/thread/mod.rs mode change 100644 => 120000 library/std/src/sys/thread/unsupported.rs mode change 100644 => 120000 library/std/src/sys/thread_local/no_threads.rs mode change 100644 => 120000 library/std/src/sys/thread_local/os.rs mode change 100644 => 120000 library/std/src/sys/time/mod.rs mode change 100644 => 120000 library/std/src/sys/time/unsupported.rs mode change 100644 => 120000 library/std/src/time.rs diff --git a/library/.gitignore b/library/.gitignore index 3885a18..7a6f012 100644 --- a/library/.gitignore +++ b/library/.gitignore @@ -12,3 +12,5 @@ rustc-std-workspace-alloc rustc-std-workspace-core rustc-std-workspace-std windows_link +test +proc_macro diff --git a/library/justfile b/library/justfile index 294bbb4..c0d1165 100644 --- a/library/justfile +++ b/library/justfile @@ -21,6 +21,11 @@ update-std: @just patch-std cp_std path: + @echo "Linking {{ path }}" + @mkdir {{ "std/src" / parent_directory(path) }} -p + @ln -fs {{ RUST_SRC / "std/src" / path }} {{ "std/src" / parent_directory(path) }} + +real_cp_std path: @echo "Copying {{ path }}" @mkdir {{ "std/src" / parent_directory(path) }} -p @cp {{ RUST_SRC / "std/src" / path }} {{ "std/src" / path }} @@ -43,7 +48,9 @@ setup-std: ln -fs {{ RUST_SRC / "profiler_builtins" }} "." ln -fs {{ RUST_SRC / "test" }} "." - @# Complete + @just cp_std "../build.rs" + @sed -i "59a\ || target_os == \"survos\"" std/build.rs + @just cp_std "alloc.rs" @just cp_std "ascii.rs" @just cp_std "backtrace.rs" @@ -61,51 +68,38 @@ setup-std: @just cp_std "process.rs" @just cp_std "random.rs" @just cp_std "rt.rs" - # @just cp_std "tests_helpers.rs" + @just cp_std "tests_helpers.rs" @just cp_std "time.rs" - @# Complete - ln -fs {{ RUST_SRC / "std/src/backtrace" }} "std/src/" + @just cp_std "backtrace" - @# Complete - ln -fs {{ RUST_SRC / "std/src/collections" }} "std/src/" + @just cp_std "collections" - @# Complete - ln -fs {{ RUST_SRC / "std/src/ffi" }} "std/src/" + @just cp_std "ffi" - @# Complete - ln -fs {{ RUST_SRC / "std/src/fs" }} "std/src/" + @just cp_std "fs" - @# Complete - ln -fs {{ RUST_SRC / "std/src/hash" }} "std/src/" + @just cp_std "hash" - @# Complete - ln -fs {{ RUST_SRC / "std/src/io" }} "std/src/" + @just cp_std "io" - @# Complete - ln -fs {{ RUST_SRC / "std/src/net" }} "std/src/" + @just cp_std "net" - @# Complete - ln -fs {{ RUST_SRC / "std/src/num" }} "std/src/" + @just cp_std "num" - @# Complete @just cp_std "os/raw/mod.rs" @just cp_std "os/raw/tests.rs" @just cp_std "os/mod.rs" - @# Complete - ln -fs {{ RUST_SRC / "std/src/prelude" }} "std/src/" + @just cp_std "prelude" - @# Complete - ln -fs {{ RUST_SRC / "std/src/process" }} "std/src/" + @just cp_std "process" - @# Complete - ln -fs {{ RUST_SRC / "std/src/sync" }} "std/src/" + @just cp_std "sync" - @# Complete @just cp_std "sys/alloc/mod.rs" - @just cp_std "sys/args/mod.rs" + @just real_cp_std "sys/args/mod.rs" @just cp_std "sys/args/unsupported.rs" @just cp_std "sys/env/mod.rs" @@ -124,7 +118,7 @@ setup-std: @just cp_std "sys/helpers/wstr.rs" @just cp_std "sys/io/error/generic.rs" - @just cp_std "sys/io/error/mod.rs" + @just real_cp_std "sys/io/error/mod.rs" @just cp_std "sys/io/io_slice/unsupported.rs" @just cp_std "sys/io/is_terminal/unsupported.rs" @just cp_std "sys/io/kernel_copy/mod.rs" @@ -140,7 +134,7 @@ setup-std: @just cp_std "sys/os_str/bytes.rs" @just cp_std "sys/os_str/mod.rs" - @just cp_std "sys/pal/mod.rs" + @just real_cp_std "sys/pal/mod.rs" @just cp_std "sys/pal/unsupported/mod.rs" @just cp_std "sys/pal/unsupported/common.rs" @just cp_std "sys/pal/unsupported/os.rs" @@ -162,7 +156,7 @@ setup-std: @just cp_std "sys/process/env.rs" @just cp_std "sys/process/unsupported.rs" - @just cp_std "sys/random/mod.rs" + @just real_cp_std "sys/random/mod.rs" @just cp_std "sys/random/unsupported.rs" @just cp_std "sys/stdio/mod.rs" @@ -184,7 +178,7 @@ setup-std: @just cp_std "sys/thread/mod.rs" @just cp_std "sys/thread/unsupported.rs" - @just cp_std "sys/thread_local/mod.rs" + @just real_cp_std "sys/thread_local/mod.rs" @just cp_std "sys/thread_local/no_threads.rs" @just cp_std "sys/thread_local/os.rs" @@ -198,8 +192,115 @@ setup-std: @just cp_std "sys/exit.rs" @just cp_std "sys/mod.rs" - @# Complete - ln -fs {{ RUST_SRC / "std/src/thread" }} "std/src/" + @just cp_std "thread" + +STD_FILES := "alloc.rs \ +ascii.rs \ +backtrace.rs \ +bstr.rs \ +env.rs \ +error.rs \ +fs.rs \ +keyword_docs.rs \ +lib.rs \ +macros.rs \ +panic.rs \ +panicking.rs \ +pat.rs \ +path.rs \ +process.rs \ +random.rs \ +rt.rs \ +tests_helpers.rs \ +time.rs \ +backtrace \ +collections \ +ffi \ +fs \ +hash \ +io \ +net \ +num \ +os/raw/mod.rs \ +os/raw/tests.rs \ +os/mod.rs \ +prelude \ +process \ +sync \ +sys/alloc/mod.rs \ +sys/args/mod.rs \ +sys/args/unsupported.rs \ +sys/env/mod.rs \ +sys/env/common.rs \ +sys/env/unsupported.rs \ +sys/fd/mod.rs \ +sys/fs/mod.rs \ +sys/fs/common.rs \ +sys/fs/unsupported.rs \ +sys/helpers/mod.rs \ +sys/helpers/small_c_string.rs \ +sys/helpers/tests.rs \ +sys/helpers/wstr.rs \ +sys/io/error/generic.rs \ +sys/io/error/mod.rs \ +sys/io/io_slice/unsupported.rs \ +sys/io/is_terminal/unsupported.rs \ +sys/io/kernel_copy/mod.rs \ +sys/io/mod.rs \ +sys/net/connection/mod.rs \ +sys/net/connection/unsupported.rs \ +sys/net/hostname/mod.rs \ +sys/net/hostname/unsupported.rs \ +sys/net/mod.rs \ +sys/os_str/bytes/tests.rs \ +sys/os_str/bytes.rs \ +sys/os_str/mod.rs \ +sys/pal/mod.rs \ +sys/pal/unsupported/mod.rs \ +sys/pal/unsupported/common.rs \ +sys/pal/unsupported/os.rs \ +sys/path/mod.rs \ +sys/path/unix.rs \ +sys/personality/dwarf/eh.rs \ +sys/personality/dwarf/mod.rs \ +sys/personality/dwarf/tests.rs \ +sys/personality/mod.rs \ +sys/pipe/mod.rs \ +sys/pipe/unsupported.rs \ +sys/platform_version/mod.rs \ +sys/process/mod.rs \ +sys/process/env.rs \ +sys/process/unsupported.rs \ +sys/random/mod.rs \ +sys/random/unsupported.rs \ +sys/stdio/mod.rs \ +sys/stdio/unsupported.rs \ +sys/sync/condvar/mod.rs \ +sys/sync/condvar/no_threads.rs \ +sys/sync/mutex/mod.rs \ +sys/sync/mutex/no_threads.rs \ +sys/sync/once/mod.rs \ +sys/sync/once/no_threads.rs \ +sys/sync/rwlock/mod.rs \ +sys/sync/rwlock/no_threads.rs \ +sys/sync/thread_parking/mod.rs \ +sys/sync/thread_parking/unsupported.rs \ +sys/sync/mod.rs \ +sys/sync/once_box.rs \ +sys/thread/mod.rs \ +sys/thread/unsupported.rs \ +sys/thread_local/mod.rs \ +sys/thread_local/no_threads.rs \ +sys/thread_local/os.rs \ +sys/time/mod.rs \ +sys/time/unsupported.rs \ +sys/backtrace.rs \ +sys/cmath.rs \ +sys/configure_builtins.rs \ +sys/env_consts.rs \ +sys/exit.rs \ +sys/mod.rs \ +thread" build-sysroot: update-std RUSTFLAGS="-Zforce-unstable-if-unmarked -C relocation-model=pic -C link-arg=-pie" cargo build --target ../riscv64.json @@ -208,35 +309,11 @@ build-sysroot: update-std cp target/riscv64/debug/deps/*.rlib ../sysroot/lib/rustlib/riscv64/lib clean: - cargo clean + # cargo clean rm ../sysroot/lib/rustlib/riscv64/lib/* -rf - rm -f alloc - rm -f compiler-builtins - rm -f panic_abort - rm -f panic_unwind - rm -f windows_link - rm -f portable-simd - rm -f unwind - rm -f std_detect - rm -f stdarch - rm -f rustc-std-workspace-alloc - rm -f rustc-std-workspace-core - rm -f proc_macro - rm -f profiler_builtins - rm -f test + for file in {{ STD_FILES }}; do \ + rm -rf std/src/$file; \ + done - rm -rf std/src/backtrace - rm -rf std/src/thread - rm -rf std/src/sync - rm -rf std/src/collections - rm -rf std/src/ffi - rm -rf std/src/fs - rm -rf std/src/num - rm -rf std/src/net - rm -rf std/src/io - rm -rf std/src/hash - rm -rf std/src/prelude - rm -rf std/src/process - - # rm -f Cargo.toml + rm -rf std/build.rs diff --git a/library/std/.gitignore b/library/std/.gitignore new file mode 100644 index 0000000..8f65c3a --- /dev/null +++ b/library/std/.gitignore @@ -0,0 +1,107 @@ +src/alloc.rs +src/ascii.rs +src/backtrace.rs +src/bstr.rs +src/env.rs +src/error.rs +src/fs.rs +src/keyword_docs.rs +src/lib.rs +src/macros.rs +src/panic.rs +src/panicking.rs +src/pat.rs +src/path.rs +src/process.rs +src/random.rs +src/rt.rs +src/tests_helpers.rs +src/time.rs +src/backtrace +src/collections +src/ffi +src/fs +src/hash +src/io +src/net +src/num +src/os/raw/mod.rs +src/os/raw/tests.rs +src/os/mod.rs +src/prelude +src/process +src/sync +src/sys/alloc/mod.rs +src/sys/args/mod.rs +src/sys/args/unsupported.rs +src/sys/env/mod.rs +src/sys/env/common.rs +src/sys/env/unsupported.rs +src/sys/fd/mod.rs +src/sys/fs/mod.rs +src/sys/fs/common.rs +src/sys/fs/unsupported.rs +src/sys/helpers/mod.rs +src/sys/helpers/small_c_string.rs +src/sys/helpers/tests.rs +src/sys/helpers/wstr.rs +src/sys/io/error/generic.rs +src/sys/io/error/mod.rs +src/sys/io/io_slice/unsupported.rs +src/sys/io/is_terminal/unsupported.rs +src/sys/io/kernel_copy/mod.rs +src/sys/io/mod.rs +src/sys/net/connection/mod.rs +src/sys/net/connection/unsupported.rs +src/sys/net/hostname/mod.rs +src/sys/net/hostname/unsupported.rs +src/sys/net/mod.rs +src/sys/os_str/bytes/tests.rs +src/sys/os_str/bytes.rs +src/sys/os_str/mod.rs +src/sys/pal/mod.rs +src/sys/pal/unsupported/mod.rs +src/sys/pal/unsupported/common.rs +src/sys/pal/unsupported/os.rs +src/sys/path/mod.rs +src/sys/path/unix.rs +src/sys/personality/dwarf/eh.rs +src/sys/personality/dwarf/mod.rs +src/sys/personality/dwarf/tests.rs +src/sys/personality/mod.rs +src/sys/pipe/mod.rs +src/sys/pipe/unsupported.rs +src/sys/platform_version/mod.rs +src/sys/process/mod.rs +src/sys/process/env.rs +src/sys/process/unsupported.rs +src/sys/random/mod.rs +src/sys/random/unsupported.rs +src/sys/stdio/mod.rs +src/sys/stdio/unsupported.rs +src/sys/sync/condvar/mod.rs +src/sys/sync/condvar/no_threads.rs +src/sys/sync/mutex/mod.rs +src/sys/sync/mutex/no_threads.rs +src/sys/sync/once/mod.rs +src/sys/sync/once/no_threads.rs +src/sys/sync/rwlock/mod.rs +src/sys/sync/rwlock/no_threads.rs +src/sys/sync/thread_parking/mod.rs +src/sys/sync/thread_parking/unsupported.rs +src/sys/sync/mod.rs +src/sys/sync/once_box.rs +src/sys/thread/mod.rs +src/sys/thread/unsupported.rs +src/sys/thread_local/mod.rs +src/sys/thread_local/no_threads.rs +src/sys/thread_local/os.rs +src/sys/time/mod.rs +src/sys/time/unsupported.rs +src/sys/backtrace.rs +src/sys/cmath.rs +src/sys/configure_builtins.rs +src/sys/env_consts.rs +src/sys/exit.rs +src/sys/mod.rs +src/thread diff --git a/library/std/build.rs b/library/std/build.rs index f151fa8..362fc29 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -1,8 +1,107 @@ use std::env; -pub fn main() { - println!( - "cargo:rustc-env=STD_ENV_ARCH={}", - env::var("CARGO_CFG_TARGET_ARCH").unwrap() - ); +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set"); + let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); + let target_vendor = + env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set"); + let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set"); + + println!("cargo:rustc-check-cfg=cfg(netbsd10)"); + if target_os == "netbsd" && env::var("RUSTC_STD_NETBSD10").is_ok() { + println!("cargo:rustc-cfg=netbsd10"); + } + + // Needed for `#![doc(auto_cfg(hide(no_global_oom_handling)))]` attribute. + println!("cargo::rustc-check-cfg=cfg(no_global_oom_handling)"); + + println!("cargo:rustc-check-cfg=cfg(restricted_std)"); + if target_os == "linux" + || target_os == "android" + || target_os == "netbsd" + || target_os == "dragonfly" + || target_os == "openbsd" + || target_os == "freebsd" + || target_os == "solaris" + || target_os == "illumos" + || target_os == "macos" + || target_os == "ios" + || target_os == "tvos" + || target_os == "watchos" + || target_os == "visionos" + || target_os == "windows" + || target_os == "fuchsia" + || (target_vendor == "fortanix" && target_env == "sgx") + || target_os == "motor" + || target_os == "hermit" + || target_os == "trusty" + || target_os == "l4re" + || target_os == "redox" + || target_os == "haiku" + || target_os == "vxworks" + || target_arch == "wasm32" + || target_arch == "wasm64" + || target_os == "espidf" + || target_os.starts_with("solid") + || (target_vendor == "nintendo" && target_env == "newlib") + || target_os == "vita" + || target_os == "aix" + || target_os == "nto" + || target_os == "xous" + || target_os == "hurd" + || target_os == "uefi" + || target_os == "teeos" + || target_os == "zkvm" + || target_os == "rtems" + || target_os == "nuttx" + || target_os == "cygwin" + || target_os == "vexos" + || target_os == "survos" + + // See src/bootstrap/src/core/build_steps/synthetic_targets.rs + || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() + { + // These platforms don't have any special requirements. + } else { + // This is for Cargo's build-std support, to mark std as unstable for + // typically no_std platforms. + // This covers: + // - os=none ("bare metal" targets) + // - mipsel-sony-psp + // - nvptx64-nvidia-cuda + // - arch=avr + // - JSON targets + // - Any new targets that have not been explicitly added above. + println!("cargo:rustc-cfg=restricted_std"); + } + + println!("cargo:rustc-check-cfg=cfg(backtrace_in_libstd)"); + println!("cargo:rustc-cfg=backtrace_in_libstd"); + + println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); + + println!("cargo:rustc-check-cfg=cfg(vxworks_lt_25_09)"); + + if target_os == "vxworks" { + match vxworks_version_code() { + Some((major, minor)) if (major, minor) < (25, 9) => { + println!("cargo:rustc-cfg=vxworks_lt_25_09"); + } + _ => {} + } + } +} + +/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build +/// environment, in `(minor, patch)` form. +fn vxworks_version_code() -> Option<(u32, u32)> { + let version = env::var("WIND_RELEASE_ID").ok()?; + + let mut pieces = version.trim().split(['.']); + + let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + + Some((major, minor)) } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs deleted file mode 100644 index ed0322e..0000000 --- a/library/std/src/alloc.rs +++ /dev/null @@ -1,490 +0,0 @@ -//! Memory allocation APIs. -//! -//! In a given program, the standard library has one “global” memory allocator -//! that is used for example by `Box` and `Vec`. -//! -//! Currently the default global allocator is unspecified. Libraries, however, -//! like `cdylib`s and `staticlib`s are guaranteed to use the [`System`] by -//! default. -//! -//! # The `#[global_allocator]` attribute -//! -//! This attribute allows configuring the choice of global allocator. -//! You can use this to implement a completely custom global allocator -//! to route all[^system-alloc] default allocation requests to a custom object. -//! -//! ```rust -//! use std::alloc::{GlobalAlloc, System, Layout}; -//! -//! struct MyAllocator; -//! -//! unsafe impl GlobalAlloc for MyAllocator { -//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -//! unsafe { System.alloc(layout) } -//! } -//! -//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -//! unsafe { System.dealloc(ptr, layout) } -//! } -//! } -//! -//! #[global_allocator] -//! static GLOBAL: MyAllocator = MyAllocator; -//! -//! fn main() { -//! // This `Vec` will allocate memory through `GLOBAL` above -//! let mut v = Vec::new(); -//! v.push(1); -//! } -//! ``` -//! -//! The attribute is used on a `static` item whose type implements the -//! [`GlobalAlloc`] trait. This type can be provided by an external library: -//! -//! ```rust,ignore (demonstrates crates.io usage) -//! use jemallocator::Jemalloc; -//! -//! #[global_allocator] -//! static GLOBAL: Jemalloc = Jemalloc; -//! -//! fn main() {} -//! ``` -//! -//! The `#[global_allocator]` can only be used once in a crate -//! or its recursive dependencies. -//! -//! [^system-alloc]: Note that the Rust standard library internals may still -//! directly call [`System`] when necessary (for example for the runtime -//! support typically required to implement a global allocator, see [re-entrance] on [`GlobalAlloc`] -//! for more details). -//! -//! [re-entrance]: trait.GlobalAlloc.html#re-entrance - -#![deny(unsafe_op_in_unsafe_fn)] -#![stable(feature = "alloc_module", since = "1.28.0")] - -use core::ptr::NonNull; -use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; -use core::{hint, mem, ptr}; - -#[stable(feature = "alloc_module", since = "1.28.0")] -#[doc(inline)] -pub use alloc_crate::alloc::*; - -/// The default memory allocator provided by the operating system. -/// -/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows, -/// plus related functions. However, it is not valid to mix use of the backing -/// system allocator with `System`, as this implementation may include extra -/// work, such as to serve alignment requests greater than the alignment -/// provided directly by the backing system allocator. -/// -/// This type implements the [`GlobalAlloc`] trait. Currently the default -/// global allocator is unspecified. Libraries, however, like `cdylib`s and -/// `staticlib`s are guaranteed to use the [`System`] by default and as such -/// work as if they had this definition: -/// -/// ```rust -/// use std::alloc::System; -/// -/// #[global_allocator] -/// static A: System = System; -/// -/// fn main() { -/// let a = Box::new(4); // Allocates from the system allocator. -/// println!("{a}"); -/// } -/// ``` -/// -/// You can also define your own wrapper around `System` if you'd like, such as -/// keeping track of the number of all bytes allocated: -/// -/// ```rust -/// use std::alloc::{System, GlobalAlloc, Layout}; -/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; -/// -/// struct Counter; -/// -/// static ALLOCATED: AtomicUsize = AtomicUsize::new(0); -/// -/// unsafe impl GlobalAlloc for Counter { -/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { -/// let ret = unsafe { System.alloc(layout) }; -/// if !ret.is_null() { -/// ALLOCATED.fetch_add(layout.size(), Relaxed); -/// } -/// ret -/// } -/// -/// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { -/// unsafe { System.dealloc(ptr, layout); } -/// ALLOCATED.fetch_sub(layout.size(), Relaxed); -/// } -/// } -/// -/// #[global_allocator] -/// static A: Counter = Counter; -/// -/// fn main() { -/// println!("allocated bytes before main: {}", ALLOCATED.load(Relaxed)); -/// } -/// ``` -/// -/// It can also be used directly to allocate memory independently of whatever -/// global allocator has been selected for a Rust program. For example if a Rust -/// program opts in to using jemalloc as the global allocator, `System` will -/// still allocate memory using `malloc` and `HeapAlloc`. -#[stable(feature = "alloc_system_type", since = "1.28.0")] -#[derive(Debug, Default, Copy, Clone)] -pub struct System; - -impl System { - #[inline] - fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { - match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)), - // SAFETY: `layout` is non-zero in size, - size => unsafe { - let raw_ptr = if zeroed { - GlobalAlloc::alloc_zeroed(self, layout) - } else { - GlobalAlloc::alloc(self, layout) - }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, size)) - }, - } - } - - // SAFETY: Same as `Allocator::grow` - #[inline] - unsafe fn grow_impl( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - zeroed: bool, - ) -> Result, AllocError> { - debug_assert!( - new_layout.size() >= old_layout.size(), - "`new_layout.size()` must be greater than or equal to `old_layout.size()`" - ); - - match old_layout.size() { - 0 => self.alloc_impl(new_layout, zeroed), - - // SAFETY: `new_size` is non-zero as `new_size` is greater than or equal to `old_size` - // as required by safety conditions and the `old_size == 0` case was handled in the - // previous match arm. Other conditions must be upheld by the caller - old_size if old_layout.align() == new_layout.align() => unsafe { - let new_size = new_layout.size(); - - // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. - hint::assert_unchecked(new_size >= old_layout.size()); - - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - if zeroed { - raw_ptr.add(old_size).write_bytes(0, new_size - old_size); - } - Ok(NonNull::slice_from_raw_parts(ptr, new_size)) - }, - - // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, - // both the old and new memory allocation are valid for reads and writes for `old_size` - // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap - // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract - // for `dealloc` must be upheld by the caller. - old_size => unsafe { - let new_ptr = self.alloc_impl(new_layout, zeroed)?; - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - Allocator::deallocate(self, ptr, old_layout); - Ok(new_ptr) - }, - } - } -} - -// The Allocator impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, -// which is in `std::sys::*::alloc`. -#[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl Allocator for System { - #[inline] - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, false) - } - - #[inline] - fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, true) - } - - #[inline] - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - if layout.size() != 0 { - // SAFETY: `layout` is non-zero in size, - // other conditions must be upheld by the caller - unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } - } - } - - #[inline] - unsafe fn grow( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } - } - - #[inline] - unsafe fn grow_zeroed( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } - } - - #[inline] - unsafe fn shrink( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - debug_assert!( - new_layout.size() <= old_layout.size(), - "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" - ); - - match new_layout.size() { - // SAFETY: conditions must be upheld by the caller - 0 => unsafe { - Allocator::deallocate(self, ptr, old_layout); - Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0)) - }, - - // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size if old_layout.align() == new_layout.align() => unsafe { - // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. - hint::assert_unchecked(new_size <= old_layout.size()); - - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, new_size)) - }, - - // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, - // both the old and new memory allocation are valid for reads and writes for `new_size` - // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap - // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract - // for `dealloc` must be upheld by the caller. - new_size => unsafe { - let new_ptr = Allocator::allocate(self, new_layout)?; - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - Allocator::deallocate(self, ptr, old_layout); - Ok(new_ptr) - }, - } - } -} - -static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); - -/// Registers a custom allocation error hook, replacing any that was previously registered. -/// -/// The allocation error hook is invoked when an infallible memory allocation fails — that is, -/// as a consequence of calling [`handle_alloc_error`] — before the runtime aborts. -/// -/// The allocation error hook is a global resource. [`take_alloc_error_hook`] may be used to -/// retrieve a previously registered hook and wrap or discard it. -/// -/// # What the provided `hook` function should expect -/// -/// The hook function is provided with a [`Layout`] struct which contains information -/// about the allocation that failed. -/// -/// The hook function may choose to panic or abort; in the event that it returns normally, this -/// will cause an immediate abort. -/// -/// Since [`take_alloc_error_hook`] is a safe function that allows retrieving the hook, the hook -/// function must be _sound_ to call even if no memory allocations were attempted. -/// -/// # The default hook -/// -/// The default hook, used if [`set_alloc_error_hook`] is never called, prints a message to -/// standard error (and then returns, causing the runtime to abort the process). -/// Compiler options may cause it to panic instead, and the default behavior may be changed -/// to panicking in future versions of Rust. -/// -/// # Examples -/// -/// ``` -/// #![feature(alloc_error_hook)] -/// -/// use std::alloc::{Layout, set_alloc_error_hook}; -/// -/// fn custom_alloc_error_hook(layout: Layout) { -/// panic!("memory allocation of {} bytes failed", layout.size()); -/// } -/// -/// set_alloc_error_hook(custom_alloc_error_hook); -/// ``` -#[unstable(feature = "alloc_error_hook", issue = "51245")] -pub fn set_alloc_error_hook(hook: fn(Layout)) { - HOOK.store(hook as *mut (), Ordering::Release); -} - -/// Unregisters the current allocation error hook, returning it. -/// -/// *See also the function [`set_alloc_error_hook`].* -/// -/// If no custom hook is registered, the default hook will be returned. -#[unstable(feature = "alloc_error_hook", issue = "51245")] -pub fn take_alloc_error_hook() -> fn(Layout) { - let hook = HOOK.swap(ptr::null_mut(), Ordering::Acquire); - if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } -} - -#[optimize(size)] -fn default_alloc_error_hook(layout: Layout) { - if cfg!(panic = "immediate-abort") { - return; - } - - // This is the default path taken on OOM, and the only path taken on stable with std. - // Crucially, it does *not* call any user-defined code, and therefore users do not have to - // worry about allocation failure causing reentrancy issues. That makes it different from - // the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error - // handler that is called when there is no `#[alloc_error_handler]`), which triggers a - // regular panic and thus can invoke a user-defined panic hook, executing arbitrary - // user-defined code. - - static PREV_ALLOC_FAILURE: AtomicBool = AtomicBool::new(false); - if PREV_ALLOC_FAILURE.swap(true, Ordering::Relaxed) { - // Don't try to print a backtrace if a previous alloc error happened. This likely means - // there is not enough memory to print a backtrace, although it could also mean that two - // threads concurrently run out of memory. - rtprintpanic!( - "memory allocation of {} bytes failed\nskipping backtrace printing to avoid potential recursion\n", - layout.size() - ); - return; - } else { - rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); - } - - let Some(mut out) = crate::sys::stdio::panic_output() else { - return; - }; - - // Use a lock to prevent mixed output in multithreading context. - // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. - // Make sure to not take this lock until after checking PREV_ALLOC_FAILURE to avoid deadlocks - // when there is too little memory to print a backtrace. - let mut lock = crate::sys::backtrace::lock(); - - match crate::panic::get_backtrace_style() { - Some(crate::panic::BacktraceStyle::Short) => { - drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Short)) - } - Some(crate::panic::BacktraceStyle::Full) => { - drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Full)) - } - Some(crate::panic::BacktraceStyle::Off) => { - use crate::io::Write; - let _ = writeln!( - out, - "note: run with `RUST_BACKTRACE=1` environment variable to display a \ - backtrace" - ); - if cfg!(miri) { - let _ = writeln!( - out, - "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \ - for the environment variable to have an effect" - ); - } - } - // If backtraces aren't supported or are forced-off, do nothing. - None => {} - } -} - -#[cfg(not(test))] -#[doc(hidden)] -#[alloc_error_handler] -#[unstable(feature = "alloc_internals", issue = "none")] -pub fn rust_oom(layout: Layout) -> ! { - crate::sys::backtrace::__rust_end_short_backtrace(|| { - let hook = HOOK.load(Ordering::Acquire); - let hook: fn(Layout) = - if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; - hook(layout); - crate::process::abort() - }) -} - -#[cfg(not(test))] -#[doc(hidden)] -#[allow(unused_attributes)] -#[unstable(feature = "alloc_internals", issue = "none")] -pub mod __default_lib_allocator { - use super::{GlobalAlloc, Layout, System}; - // These magic symbol names are used as a fallback for implementing the - // `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is - // no `#[global_allocator]` attribute. - - // for symbol names src/librustc_ast/expand/allocator.rs - // for signatures src/librustc_allocator/lib.rs - - // linkage directives are provided as part of the current compiler allocator - // ABI - - #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { - // SAFETY: see the guarantees expected by `Layout::from_size_align` and - // `GlobalAlloc::alloc`. - unsafe { - let layout = Layout::from_size_align_unchecked(size, align); - System.alloc(layout) - } - } - - #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - // SAFETY: see the guarantees expected by `Layout::from_size_align` and - // `GlobalAlloc::dealloc`. - unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) } - } - - #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rdl_realloc( - ptr: *mut u8, - old_size: usize, - align: usize, - new_size: usize, - ) -> *mut u8 { - // SAFETY: see the guarantees expected by `Layout::from_size_align` and - // `GlobalAlloc::realloc`. - unsafe { - let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr, old_layout, new_size) - } - } - - #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { - // SAFETY: see the guarantees expected by `Layout::from_size_align` and - // `GlobalAlloc::alloc_zeroed`. - unsafe { - let layout = Layout::from_size_align_unchecked(size, align); - System.alloc_zeroed(layout) - } - } -} diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs new file mode 120000 index 0000000..be05cb9 --- /dev/null +++ b/library/std/src/alloc.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/alloc.rs \ No newline at end of file diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs deleted file mode 100644 index 3813f32..0000000 --- a/library/std/src/ascii.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! Operations on ASCII strings and characters. -//! -//! Most string operations in Rust act on UTF-8 strings. However, at times it -//! makes more sense to only consider the ASCII character set for a specific -//! operation. -//! -//! The [`AsciiExt`] trait provides methods that allow for character -//! operations that only act on the ASCII subset and leave non-ASCII characters -//! alone. -//! -//! The [`escape_default`] function provides an iterator over the bytes of an -//! escaped version of the character given. - -#![stable(feature = "rust1", since = "1.0.0")] - -#[unstable(feature = "ascii_char", issue = "110998")] -pub use core::ascii::Char; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::ascii::{EscapeDefault, escape_default}; - -/// Extension methods for ASCII-subset only operations. -/// -/// Be aware that operations on seemingly non-ASCII characters can sometimes -/// have unexpected results. Consider this example: -/// -/// ``` -/// use std::ascii::AsciiExt; -/// -/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ"); -/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé"); -/// ``` -/// -/// In the first example, the lowercased string is represented `"cafe\u{301}"` -/// (the last character is an acute accent [combining character]). Unlike the -/// other characters in the string, the combining character will not get mapped -/// to an uppercase variant, resulting in `"CAFE\u{301}"`. In the second -/// example, the lowercased string is represented `"caf\u{e9}"` (the last -/// character is a single Unicode character representing an 'e' with an acute -/// accent). Since the last character is defined outside the scope of ASCII, -/// it will not get mapped to an uppercase variant, resulting in `"CAF\u{e9}"`. -/// -/// [combining character]: https://en.wikipedia.org/wiki/Combining_character -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.26.0", note = "use inherent methods instead")] -pub trait AsciiExt { - /// Container type for copied ASCII characters. - #[stable(feature = "rust1", since = "1.0.0")] - type Owned; - - /// Checks if the value is within the ASCII range. - /// - /// # Note - /// - /// This method is deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[stable(feature = "rust1", since = "1.0.0")] - fn is_ascii(&self) -> bool; - - /// Makes a copy of the value in its ASCII upper case equivalent. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To uppercase the value in-place, use [`make_ascii_uppercase`]. - /// - /// To uppercase ASCII characters in addition to non-ASCII characters, use - /// [`str::to_uppercase`]. - /// - /// # Note - /// - /// This method is deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`make_ascii_uppercase`]: AsciiExt::make_ascii_uppercase - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - fn to_ascii_uppercase(&self) -> Self::Owned; - - /// Makes a copy of the value in its ASCII lower case equivalent. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To lowercase the value in-place, use [`make_ascii_lowercase`]. - /// - /// To lowercase ASCII characters in addition to non-ASCII characters, use - /// [`str::to_lowercase`]. - /// - /// # Note - /// - /// This method is deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`make_ascii_lowercase`]: AsciiExt::make_ascii_lowercase - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - fn to_ascii_lowercase(&self) -> Self::Owned; - - /// Checks that two values are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - /// - /// # Note - /// - /// This method is deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[stable(feature = "rust1", since = "1.0.0")] - fn eq_ignore_ascii_case(&self, other: &Self) -> bool; - - /// Converts this type to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// # Note - /// - /// This method is deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`to_ascii_uppercase`]: AsciiExt::to_ascii_uppercase - #[stable(feature = "ascii", since = "1.9.0")] - fn make_ascii_uppercase(&mut self); - - /// Converts this type to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// # Note - /// - /// This method is deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - /// - /// [`to_ascii_lowercase`]: AsciiExt::to_ascii_lowercase - #[stable(feature = "ascii", since = "1.9.0")] - fn make_ascii_lowercase(&mut self); -} - -macro_rules! delegating_ascii_methods { - () => { - #[inline] - fn is_ascii(&self) -> bool { - self.is_ascii() - } - - #[inline] - fn to_ascii_uppercase(&self) -> Self::Owned { - self.to_ascii_uppercase() - } - - #[inline] - fn to_ascii_lowercase(&self) -> Self::Owned { - self.to_ascii_lowercase() - } - - #[inline] - fn eq_ignore_ascii_case(&self, o: &Self) -> bool { - self.eq_ignore_ascii_case(o) - } - - #[inline] - fn make_ascii_uppercase(&mut self) { - self.make_ascii_uppercase(); - } - - #[inline] - fn make_ascii_lowercase(&mut self) { - self.make_ascii_lowercase(); - } - }; -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for u8 { - type Owned = u8; - - delegating_ascii_methods!(); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for char { - type Owned = char; - - delegating_ascii_methods!(); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for [u8] { - type Owned = Vec; - - delegating_ascii_methods!(); -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl AsciiExt for str { - type Owned = String; - - delegating_ascii_methods!(); -} diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs new file mode 120000 index 0000000..ebc37f8 --- /dev/null +++ b/library/std/src/ascii.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/ascii.rs \ No newline at end of file diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs deleted file mode 100644 index 99724e2..0000000 --- a/library/std/src/backtrace.rs +++ /dev/null @@ -1,478 +0,0 @@ -//! Support for capturing a stack backtrace of an OS thread -//! -//! This module contains the support necessary to capture a stack backtrace of a -//! running OS thread from the OS thread itself. The `Backtrace` type supports -//! capturing a stack trace via the `Backtrace::capture` and -//! `Backtrace::force_capture` functions. -//! -//! A backtrace is typically quite handy to attach to errors (e.g. types -//! implementing `std::error::Error`) to get a causal chain of where an error -//! was generated. -//! -//! ## Accuracy -//! -//! Backtraces are attempted to be as accurate as possible, but no guarantees -//! are provided about the exact accuracy of a backtrace. Instruction pointers, -//! symbol names, filenames, line numbers, etc, may all be incorrect when -//! reported. Accuracy is attempted on a best-effort basis, however, any bug -//! reports are always welcome to indicate areas of improvement! -//! -//! For most platforms a backtrace with a filename/line number requires that -//! programs be compiled with debug information. Without debug information -//! filenames/line numbers will not be reported. -//! -//! ## Platform support -//! -//! Not all platforms that std compiles for support capturing backtraces. Some -//! platforms simply do nothing when capturing a backtrace. To check whether the -//! platform supports capturing backtraces you can consult the `BacktraceStatus` -//! enum as a result of `Backtrace::status`. -//! -//! Like above with accuracy platform support is done on a best effort basis. -//! Sometimes libraries might not be available at runtime or something may go -//! wrong which would cause a backtrace to not be captured. Please feel free to -//! report issues with platforms where a backtrace cannot be captured though! -//! -//! ## Environment Variables -//! -//! The `Backtrace::capture` function might not actually capture a backtrace by -//! default. Its behavior is governed by two environment variables: -//! -//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture` -//! will never capture a backtrace. Any other value set will enable -//! `Backtrace::capture`. -//! -//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable -//! is consulted with the same rules of `RUST_LIB_BACKTRACE`. -//! -//! * If neither of the above env vars are set, then `Backtrace::capture` will -//! be disabled. -//! -//! Capturing a backtrace can be a quite expensive runtime operation, so the -//! environment variables allow either forcibly disabling this runtime -//! performance hit or allow selectively enabling it in some programs. -//! -//! Note that the `Backtrace::force_capture` function can be used to ignore -//! these environment variables. Also note that the state of environment -//! variables is cached once the first backtrace is created, so altering -//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change -//! how backtraces are captured. - -#![stable(feature = "backtrace", since = "1.65.0")] - -#[cfg(test)] -mod tests; - -// NB: A note on resolution of a backtrace: -// -// Backtraces primarily happen in two steps, one is where we actually capture -// the stack backtrace, giving us a list of instruction pointers corresponding -// to stack frames. Next we take these instruction pointers and, one-by-one, -// turn them into a human readable name (like `main`). -// -// The first phase can be somewhat expensive (walking the stack), especially -// on MSVC where debug information is consulted to return inline frames each as -// their own frame. The second phase, however, is almost always extremely -// expensive (on the order of milliseconds sometimes) when it's consulting debug -// information. -// -// We attempt to amortize this cost as much as possible by delaying resolution -// of an address to a human readable name for as long as possible. When -// `Backtrace::create` is called to capture a backtrace it doesn't actually -// perform any symbol resolution, but rather we lazily resolve symbols only just -// before they're needed for printing. This way we can make capturing a -// backtrace and throwing it away much cheaper, but actually printing a -// backtrace is still basically the same cost. -// -// This strategy comes at the cost of some synchronization required inside of a -// `Backtrace`, but that's a relatively small price to pay relative to capturing -// a backtrace or actually symbolizing it. - -use crate::backtrace_rs::{self, BytesOrWideString}; -use crate::ffi::c_void; -use crate::panic::UnwindSafe; -use crate::sync::LazyLock; -use crate::sync::atomic::Ordering::Relaxed; -use crate::sync::atomic::{Atomic, AtomicU8}; -use crate::sys::backtrace::{lock, output_filename, set_image_base}; -use crate::{env, fmt}; - -/// A captured OS thread stack backtrace. -/// -/// This type represents a stack backtrace for an OS thread captured at a -/// previous point in time. In some instances the `Backtrace` type may -/// internally be empty due to configuration. For more information see -/// `Backtrace::capture`. -#[stable(feature = "backtrace", since = "1.65.0")] -#[must_use] -pub struct Backtrace { - inner: Inner, -} - -/// The current status of a backtrace, indicating whether it was captured or -/// whether it is empty for some other reason. -#[stable(feature = "backtrace", since = "1.65.0")] -#[non_exhaustive] -#[derive(Debug, PartialEq, Eq)] -pub enum BacktraceStatus { - /// Capturing a backtrace is not supported, likely because it's not - /// implemented for the current platform. - #[stable(feature = "backtrace", since = "1.65.0")] - Unsupported, - /// Capturing a backtrace has been disabled through either the - /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables. - #[stable(feature = "backtrace", since = "1.65.0")] - Disabled, - /// A backtrace has been captured and the `Backtrace` should print - /// reasonable information when rendered. - #[stable(feature = "backtrace", since = "1.65.0")] - Captured, -} - -enum Inner { - Unsupported, - Disabled, - Captured(LazyLock), -} - -struct Capture { - actual_start: usize, - frames: Vec, -} - -fn _assert_send_sync() { - fn _assert() {} - _assert::(); -} - -/// A single frame of a backtrace. -#[unstable(feature = "backtrace_frames", issue = "79676")] -pub struct BacktraceFrame { - frame: RawFrame, - symbols: Vec, -} - -#[derive(Debug)] -enum RawFrame { - Actual(backtrace_rs::Frame), - #[cfg(test)] - Fake, -} - -struct BacktraceSymbol { - name: Option>, - filename: Option, - lineno: Option, - colno: Option, -} - -enum BytesOrWide { - Bytes(Vec), - Wide(Vec), -} - -#[stable(feature = "backtrace", since = "1.65.0")] -impl fmt::Debug for Backtrace { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let capture = match &self.inner { - Inner::Unsupported => return fmt.write_str(""), - Inner::Disabled => return fmt.write_str(""), - Inner::Captured(c) => &**c, - }; - - let frames = &capture.frames[capture.actual_start..]; - - write!(fmt, "Backtrace ")?; - - let mut dbg = fmt.debug_list(); - - for frame in frames { - if frame.frame.ip().is_null() { - continue; - } - - dbg.entries(&frame.symbols); - } - - dbg.finish() - } -} - -#[unstable(feature = "backtrace_frames", issue = "79676")] -impl fmt::Debug for BacktraceFrame { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut dbg = fmt.debug_list(); - dbg.entries(&self.symbols); - dbg.finish() - } -} - -impl fmt::Debug for BacktraceSymbol { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - // FIXME: improve formatting: https://github.com/rust-lang/rust/issues/65280 - // FIXME: Also, include column numbers into the debug format as Display already has them. - // Until there are stable per-frame accessors, the format shouldn't be changed: - // https://github.com/rust-lang/rust/issues/65280#issuecomment-638966585 - write!(fmt, "{{ ")?; - - if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) { - write!(fmt, "fn: \"{:#}\"", fn_name)?; - } else { - write!(fmt, "fn: ")?; - } - - if let Some(fname) = self.filename.as_ref() { - write!(fmt, ", file: \"{:?}\"", fname)?; - } - - if let Some(line) = self.lineno { - write!(fmt, ", line: {:?}", line)?; - } - - write!(fmt, " }}") - } -} - -impl fmt::Debug for BytesOrWide { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - output_filename( - fmt, - match self { - BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), - BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), - }, - backtrace_rs::PrintFmt::Short, - crate::env::current_dir().as_ref().ok(), - ) - } -} - -impl Backtrace { - /// Returns whether backtrace captures are enabled through environment - /// variables. - fn enabled() -> bool { - // Cache the result of reading the environment variables to make - // backtrace captures speedy, because otherwise reading environment - // variables every time can be somewhat slow. - static ENABLED: Atomic = AtomicU8::new(0); - match ENABLED.load(Relaxed) { - 0 => {} - 1 => return false, - _ => return true, - } - let enabled = match env::var("RUST_LIB_BACKTRACE") { - Ok(s) => s != "0", - Err(_) => match env::var("RUST_BACKTRACE") { - Ok(s) => s != "0", - Err(_) => false, - }, - }; - ENABLED.store(enabled as u8 + 1, Relaxed); - enabled - } - - /// Captures a stack backtrace of the current thread. - /// - /// This function will capture a stack backtrace of the current OS thread of - /// execution, returning a `Backtrace` type which can be later used to print - /// the entire stack trace or render it to a string. - /// - /// This function will be a noop if the `RUST_BACKTRACE` or - /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either - /// environment variable is set and enabled then this function will actually - /// capture a backtrace. Capturing a backtrace can be both memory intensive - /// and slow, so these environment variables allow liberally using - /// `Backtrace::capture` and only incurring a slowdown when the environment - /// variables are set. - /// - /// To forcibly capture a backtrace regardless of environment variables, use - /// the `Backtrace::force_capture` function. - #[stable(feature = "backtrace", since = "1.65.0")] - #[inline(never)] // want to make sure there's a frame here to remove - pub fn capture() -> Backtrace { - if !Backtrace::enabled() { - return Backtrace { inner: Inner::Disabled }; - } - Backtrace::create(Backtrace::capture as fn() -> Backtrace as usize) - } - - /// Forcibly captures a full backtrace, regardless of environment variable - /// configuration. - /// - /// This function behaves the same as `capture` except that it ignores the - /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment - /// variables, always capturing a backtrace. - /// - /// Note that capturing a backtrace can be an expensive operation on some - /// platforms, so this should be used with caution in performance-sensitive - /// parts of code. - #[stable(feature = "backtrace", since = "1.65.0")] - #[inline(never)] // want to make sure there's a frame here to remove - pub fn force_capture() -> Backtrace { - Backtrace::create(Backtrace::force_capture as fn() -> Backtrace as usize) - } - - /// Forcibly captures a disabled backtrace, regardless of environment - /// variable configuration. - #[stable(feature = "backtrace", since = "1.65.0")] - #[rustc_const_stable(feature = "backtrace", since = "1.65.0")] - pub const fn disabled() -> Backtrace { - Backtrace { inner: Inner::Disabled } - } - - // Capture a backtrace which start just before the function addressed by - // `ip` - fn create(ip: usize) -> Backtrace { - let _lock = lock(); - let mut frames = Vec::new(); - let mut actual_start = None; - set_image_base(); - unsafe { - backtrace_rs::trace_unsynchronized(|frame| { - frames.push(BacktraceFrame { - frame: RawFrame::Actual(frame.clone()), - symbols: Vec::new(), - }); - if frame.symbol_address().addr() == ip && actual_start.is_none() { - actual_start = Some(frames.len()); - } - true - }); - } - - // If no frames came out assume that this is an unsupported platform - // since `backtrace` doesn't provide a way of learning this right now, - // and this should be a good enough approximation. - let inner = if frames.is_empty() { - Inner::Unsupported - } else { - Inner::Captured(LazyLock::new(lazy_resolve(Capture { - actual_start: actual_start.unwrap_or(0), - frames, - }))) - }; - - Backtrace { inner } - } - - /// Returns the status of this backtrace, indicating whether this backtrace - /// request was unsupported, disabled, or a stack trace was actually - /// captured. - #[stable(feature = "backtrace", since = "1.65.0")] - #[must_use] - pub fn status(&self) -> BacktraceStatus { - match self.inner { - Inner::Unsupported => BacktraceStatus::Unsupported, - Inner::Disabled => BacktraceStatus::Disabled, - Inner::Captured(_) => BacktraceStatus::Captured, - } - } -} - -impl<'a> Backtrace { - /// Returns an iterator over the backtrace frames. - #[must_use] - #[unstable(feature = "backtrace_frames", issue = "79676")] - pub fn frames(&'a self) -> &'a [BacktraceFrame] { - if let Inner::Captured(c) = &self.inner { &c.frames } else { &[] } - } -} - -#[stable(feature = "backtrace", since = "1.65.0")] -impl fmt::Display for Backtrace { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let capture = match &self.inner { - Inner::Unsupported => return fmt.write_str("unsupported backtrace"), - Inner::Disabled => return fmt.write_str("disabled backtrace"), - Inner::Captured(c) => &**c, - }; - - let full = fmt.alternate(); - let (frames, style) = if full { - (&capture.frames[..], backtrace_rs::PrintFmt::Full) - } else { - (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short) - }; - - // When printing paths we try to strip the cwd if it exists, otherwise - // we just print the path as-is. Note that we also only do this for the - // short format, because if it's full we presumably want to print - // everything. - let cwd = crate::env::current_dir(); - let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| { - output_filename(fmt, path, style, cwd.as_ref().ok()) - }; - - let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path); - f.add_context()?; - for frame in frames { - if frame.symbols.is_empty() { - f.frame().print_raw(frame.frame.ip(), None, None, None)?; - } else { - for symbol in frame.symbols.iter() { - f.frame().print_raw_with_column( - frame.frame.ip(), - symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)), - symbol.filename.as_ref().map(|b| match b { - BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w), - BytesOrWide::Wide(w) => BytesOrWideString::Wide(w), - }), - symbol.lineno, - symbol.colno, - )?; - } - } - } - f.finish()?; - Ok(()) - } -} - -mod helper { - use super::*; - pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; - - #[define_opaque(LazyResolve)] - pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve { - move || { - // Use the global backtrace lock to synchronize this as it's a - // requirement of the `backtrace` crate, and then actually resolve - // everything. - let _lock = lock(); - for frame in capture.frames.iter_mut() { - let symbols = &mut frame.symbols; - let frame = match &frame.frame { - RawFrame::Actual(frame) => frame, - #[cfg(test)] - RawFrame::Fake => unimplemented!(), - }; - unsafe { - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - symbols.push(BacktraceSymbol { - name: symbol.name().map(|m| m.as_bytes().to_vec()), - filename: symbol.filename_raw().map(|b| match b { - BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), - BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), - }), - lineno: symbol.lineno(), - colno: symbol.colno(), - }); - }); - } - } - - capture - } - } -} -use helper::*; - -impl RawFrame { - fn ip(&self) -> *mut c_void { - match self { - RawFrame::Actual(frame) => frame.ip(), - #[cfg(test)] - RawFrame::Fake => crate::ptr::without_provenance_mut(1), - } - } -} diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs new file mode 120000 index 0000000..feaae68 --- /dev/null +++ b/library/std/src/backtrace.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/backtrace.rs \ No newline at end of file diff --git a/library/std/src/bstr.rs b/library/std/src/bstr.rs deleted file mode 100644 index dd49177..0000000 --- a/library/std/src/bstr.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! The `ByteStr` and `ByteString` types and trait implementations. - -#[unstable(feature = "bstr", issue = "134915")] -pub use alloc::bstr::{ByteStr, ByteString}; diff --git a/library/std/src/bstr.rs b/library/std/src/bstr.rs new file mode 120000 index 0000000..9126d94 --- /dev/null +++ b/library/std/src/bstr.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/bstr.rs \ No newline at end of file diff --git a/library/std/src/env.rs b/library/std/src/env.rs deleted file mode 100644 index edf0127..0000000 --- a/library/std/src/env.rs +++ /dev/null @@ -1,1168 +0,0 @@ -//! Inspection and manipulation of the process's environment. -//! -//! This module contains functions to inspect various aspects such as -//! environment variables, process arguments, the current directory, and various -//! other important directories. -//! -//! There are several functions and structs in this module that have a -//! counterpart ending in `os`. Those ending in `os` will return an [`OsString`] -//! and those without will return a [`String`]. - -#![stable(feature = "env", since = "1.0.0")] - -use crate::error::Error; -use crate::ffi::{OsStr, OsString}; -use crate::num::NonZero; -use crate::ops::Try; -use crate::path::{Path, PathBuf}; -use crate::sys::{env as env_imp, os as os_imp}; -use crate::{array, fmt, io, sys}; - -/// Returns the current working directory as a [`PathBuf`]. -/// -/// # Platform-specific behavior -/// -/// This function [currently] corresponds to the `getcwd` function on Unix -/// and the `GetCurrentDirectoryW` function on Windows. -/// -/// [currently]: crate::io#platform-specific-behavior -/// -/// # Errors -/// -/// Returns an [`Err`] if the current working directory value is invalid. -/// Possible cases: -/// -/// * Current directory does not exist. -/// * There are insufficient permissions to access the current directory. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// fn main() -> std::io::Result<()> { -/// let path = env::current_dir()?; -/// println!("The current directory is {}", path.display()); -/// Ok(()) -/// } -/// ``` -#[doc(alias = "pwd")] -#[doc(alias = "getcwd")] -#[doc(alias = "GetCurrentDirectory")] -#[stable(feature = "env", since = "1.0.0")] -pub fn current_dir() -> io::Result { - os_imp::getcwd() -} - -/// Changes the current working directory to the specified path. -/// -/// # Platform-specific behavior -/// -/// This function [currently] corresponds to the `chdir` function on Unix -/// and the `SetCurrentDirectoryW` function on Windows. -/// -/// Returns an [`Err`] if the operation fails. -/// -/// [currently]: crate::io#platform-specific-behavior -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// use std::path::Path; -/// -/// let root = Path::new("/"); -/// assert!(env::set_current_dir(&root).is_ok()); -/// println!("Successfully changed working directory to {}!", root.display()); -/// ``` -#[doc(alias = "chdir", alias = "SetCurrentDirectory", alias = "SetCurrentDirectoryW")] -#[stable(feature = "env", since = "1.0.0")] -pub fn set_current_dir>(path: P) -> io::Result<()> { - os_imp::chdir(path.as_ref()) -} - -/// An iterator over a snapshot of the environment variables of this process. -/// -/// This structure is created by [`env::vars()`]. See its documentation for more. -/// -/// [`env::vars()`]: vars -#[stable(feature = "env", since = "1.0.0")] -pub struct Vars { - inner: VarsOs, -} - -/// An iterator over a snapshot of the environment variables of this process. -/// -/// This structure is created by [`env::vars_os()`]. See its documentation for more. -/// -/// [`env::vars_os()`]: vars_os -#[stable(feature = "env", since = "1.0.0")] -pub struct VarsOs { - inner: env_imp::Env, -} - -/// Returns an iterator of (variable, value) pairs of strings, for all the -/// environment variables of the current process. -/// -/// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation. Modifications to environment -/// variables afterwards will not be reflected in the returned iterator. -/// -/// # Panics -/// -/// While iterating, the returned iterator will panic if any key or value in the -/// environment is not valid unicode. If this is not desired, consider using -/// [`env::vars_os()`]. -/// -/// # Examples -/// -/// ``` -/// // Print all environment variables. -/// for (key, value) in std::env::vars() { -/// println!("{key}: {value}"); -/// } -/// ``` -/// -/// [`env::vars_os()`]: vars_os -#[must_use] -#[stable(feature = "env", since = "1.0.0")] -pub fn vars() -> Vars { - Vars { inner: vars_os() } -} - -/// Returns an iterator of (variable, value) pairs of OS strings, for all the -/// environment variables of the current process. -/// -/// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation. Modifications to environment -/// variables afterwards will not be reflected in the returned iterator. -/// -/// Note that the returned iterator will not check if the environment variables -/// are valid Unicode. If you want to panic on invalid UTF-8, -/// use the [`vars`] function instead. -/// -/// # Examples -/// -/// ``` -/// // Print all environment variables. -/// for (key, value) in std::env::vars_os() { -/// println!("{key:?}: {value:?}"); -/// } -/// ``` -#[must_use] -#[stable(feature = "env", since = "1.0.0")] -pub fn vars_os() -> VarsOs { - VarsOs { inner: env_imp::env() } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for Vars { - type Item = (String, String); - fn next(&mut self) -> Option<(String, String)> { - self.inner.next().map(|(a, b)| (a.into_string().unwrap(), b.into_string().unwrap())) - } - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Vars { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { inner: VarsOs { inner } } = self; - f.debug_struct("Vars").field("inner", inner).finish() - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for VarsOs { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.inner.next() - } - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for VarsOs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { inner } = self; - f.debug_struct("VarsOs").field("inner", inner).finish() - } -} - -/// Fetches the environment variable `key` from the current process. -/// -/// # Errors -/// -/// Returns [`VarError::NotPresent`] if: -/// - The variable is not set. -/// - The variable's name contains an equal sign or NUL (`'='` or `'\0'`). -/// -/// Returns [`VarError::NotUnicode`] if the variable's value is not valid -/// Unicode. If this is not desired, consider using [`var_os`]. -/// -/// Use [`env!`] or [`option_env!`] instead if you want to check environment -/// variables at compile time. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "HOME"; -/// match env::var(key) { -/// Ok(val) => println!("{key}: {val:?}"), -/// Err(e) => println!("couldn't interpret {key}: {e}"), -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn var>(key: K) -> Result { - _var(key.as_ref()) -} - -fn _var(key: &OsStr) -> Result { - match var_os(key) { - Some(s) => s.into_string().map_err(VarError::NotUnicode), - None => Err(VarError::NotPresent), - } -} - -/// Fetches the environment variable `key` from the current process, returning -/// [`None`] if the variable isn't set or if there is another error. -/// -/// It may return `None` if the environment variable's name contains -/// the equal sign character (`=`) or the NUL character. -/// -/// Note that this function will not check if the environment variable -/// is valid Unicode. If you want to have an error on invalid UTF-8, -/// use the [`var`] function instead. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "HOME"; -/// match env::var_os(key) { -/// Some(val) => println!("{key}: {val:?}"), -/// None => println!("{key} is not defined in the environment.") -/// } -/// ``` -/// -/// If expecting a delimited variable (such as `PATH`), [`split_paths`] -/// can be used to separate items. -#[must_use] -#[stable(feature = "env", since = "1.0.0")] -pub fn var_os>(key: K) -> Option { - _var_os(key.as_ref()) -} - -fn _var_os(key: &OsStr) -> Option { - env_imp::getenv(key) -} - -/// The error type for operations interacting with environment variables. -/// Possibly returned from [`env::var()`]. -/// -/// [`env::var()`]: var -#[derive(Debug, PartialEq, Eq, Clone)] -#[stable(feature = "env", since = "1.0.0")] -pub enum VarError { - /// The specified environment variable was not present in the current - /// process's environment. - #[stable(feature = "env", since = "1.0.0")] - NotPresent, - - /// The specified environment variable was found, but it did not contain - /// valid unicode data. The found data is returned as a payload of this - /// variant. - #[stable(feature = "env", since = "1.0.0")] - NotUnicode(#[stable(feature = "env", since = "1.0.0")] OsString), -} - -#[stable(feature = "env", since = "1.0.0")] -impl fmt::Display for VarError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - VarError::NotPresent => write!(f, "environment variable not found"), - VarError::NotUnicode(ref s) => { - write!(f, "environment variable was not valid unicode: {:?}", s) - } - } - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Error for VarError {} - -/// Sets the environment variable `key` to the value `value` for the currently running -/// process. -/// -/// # Safety -/// -/// This function is safe to call in a single-threaded program. -/// -/// This function is also always safe to call on Windows, in single-threaded -/// and multi-threaded programs. -/// -/// In multi-threaded programs on other operating systems, the only safe option is -/// to not use `set_var` or `remove_var` at all. -/// -/// The exact requirement is: you -/// must ensure that there are no other threads concurrently writing or -/// *reading*(!) the environment through functions or global variables other -/// than the ones in this module. The problem is that these operating systems -/// do not provide a thread-safe way to read the environment, and most C -/// libraries, including libc itself, do not advertise which functions read -/// from the environment. Even functions from the Rust standard library may -/// read the environment without going through this module, e.g. for DNS -/// lookups from [`std::net::ToSocketAddrs`]. No stable guarantee is made about -/// which functions may read from the environment in future versions of a -/// library. All this makes it not practically possible for you to guarantee -/// that no other thread will read the environment, so the only safe option is -/// to not use `set_var` or `remove_var` in multi-threaded programs at all. -/// -/// Discussion of this unsafety on Unix may be found in: -/// -/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=188) -/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) -/// -/// To pass an environment variable to a child process, you can instead use [`Command::env`]. -/// -/// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs -/// [`Command::env`]: crate::process::Command::env -/// -/// # Panics -/// -/// This function may panic if `key` is empty, contains an ASCII equals sign `'='` -/// or the NUL character `'\0'`, or when `value` contains the NUL character. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "KEY"; -/// unsafe { -/// env::set_var(key, "VALUE"); -/// } -/// assert_eq!(env::var(key), Ok("VALUE".to_string())); -/// ``` -#[rustc_deprecated_safe_2024( - audit_that = "the environment access only happens in single-threaded code" -)] -#[stable(feature = "env", since = "1.0.0")] -pub unsafe fn set_var, V: AsRef>(key: K, value: V) { - let (key, value) = (key.as_ref(), value.as_ref()); - unsafe { env_imp::setenv(key, value) }.unwrap_or_else(|e| { - panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}") - }) -} - -/// Removes an environment variable from the environment of the currently running process. -/// -/// # Safety -/// -/// This function is safe to call in a single-threaded program. -/// -/// This function is also always safe to call on Windows, in single-threaded -/// and multi-threaded programs. -/// -/// In multi-threaded programs on other operating systems, the only safe option is -/// to not use `set_var` or `remove_var` at all. -/// -/// The exact requirement is: you -/// must ensure that there are no other threads concurrently writing or -/// *reading*(!) the environment through functions or global variables other -/// than the ones in this module. The problem is that these operating systems -/// do not provide a thread-safe way to read the environment, and most C -/// libraries, including libc itself, do not advertise which functions read -/// from the environment. Even functions from the Rust standard library may -/// read the environment without going through this module, e.g. for DNS -/// lookups from [`std::net::ToSocketAddrs`]. No stable guarantee is made about -/// which functions may read from the environment in future versions of a -/// library. All this makes it not practically possible for you to guarantee -/// that no other thread will read the environment, so the only safe option is -/// to not use `set_var` or `remove_var` in multi-threaded programs at all. -/// -/// Discussion of this unsafety on Unix may be found in: -/// -/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) -/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) -/// -/// To prevent a child process from inheriting an environment variable, you can -/// instead use [`Command::env_remove`] or [`Command::env_clear`]. -/// -/// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs -/// [`Command::env_remove`]: crate::process::Command::env_remove -/// [`Command::env_clear`]: crate::process::Command::env_clear -/// -/// # Panics -/// -/// This function may panic if `key` is empty, contains an ASCII equals sign -/// `'='` or the NUL character `'\0'`, or when the value contains the NUL -/// character. -/// -/// # Examples -/// -/// ```no_run -/// use std::env; -/// -/// let key = "KEY"; -/// unsafe { -/// env::set_var(key, "VALUE"); -/// } -/// assert_eq!(env::var(key), Ok("VALUE".to_string())); -/// -/// unsafe { -/// env::remove_var(key); -/// } -/// assert!(env::var(key).is_err()); -/// ``` -#[rustc_deprecated_safe_2024( - audit_that = "the environment access only happens in single-threaded code" -)] -#[stable(feature = "env", since = "1.0.0")] -pub unsafe fn remove_var>(key: K) { - let key = key.as_ref(); - unsafe { env_imp::unsetenv(key) } - .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}")) -} - -/// An iterator that splits an environment variable into paths according to -/// platform-specific conventions. -/// -/// The iterator element type is [`PathBuf`]. -/// -/// This structure is created by [`env::split_paths()`]. See its -/// documentation for more. -/// -/// [`env::split_paths()`]: split_paths -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "env", since = "1.0.0")] -pub struct SplitPaths<'a> { - inner: os_imp::SplitPaths<'a>, -} - -/// Parses input according to platform conventions for the `PATH` -/// environment variable. -/// -/// Returns an iterator over the paths contained in `unparsed`. The iterator -/// element type is [`PathBuf`]. -/// -/// On most Unix platforms, the separator is `:` and on Windows it is `;`. This -/// also performs unquoting on Windows. -/// -/// [`join_paths`] can be used to recombine elements. -/// -/// # Panics -/// -/// This will panic on systems where there is no delimited `PATH` variable, -/// such as UEFI. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// let key = "PATH"; -/// match env::var_os(key) { -/// Some(paths) => { -/// for path in env::split_paths(&paths) { -/// println!("'{}'", path.display()); -/// } -/// } -/// None => println!("{key} is not defined in the environment.") -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn split_paths + ?Sized>(unparsed: &T) -> SplitPaths<'_> { - SplitPaths { inner: os_imp::split_paths(unparsed.as_ref()) } -} - -#[stable(feature = "env", since = "1.0.0")] -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.inner.next() - } - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for SplitPaths<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitPaths").finish_non_exhaustive() - } -} - -/// The error type for operations on the `PATH` variable. Possibly returned from -/// [`env::join_paths()`]. -/// -/// [`env::join_paths()`]: join_paths -#[derive(Debug)] -#[stable(feature = "env", since = "1.0.0")] -pub struct JoinPathsError { - inner: os_imp::JoinPathsError, -} - -/// Joins a collection of [`Path`]s appropriately for the `PATH` -/// environment variable. -/// -/// # Errors -/// -/// Returns an [`Err`] (containing an error message) if one of the input -/// [`Path`]s contains an invalid character for constructing the `PATH` -/// variable (a double quote on Windows or a colon on Unix or semicolon on -/// UEFI), or if the system does not have a `PATH`-like variable (e.g. WASI). -/// -/// # Examples -/// -/// Joining paths on a Unix-like platform: -/// -/// ``` -/// use std::env; -/// use std::ffi::OsString; -/// use std::path::Path; -/// -/// fn main() -> Result<(), env::JoinPathsError> { -/// # if cfg!(unix) { -/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; -/// let path_os_string = env::join_paths(paths.iter())?; -/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); -/// # } -/// Ok(()) -/// } -/// ``` -/// -/// Joining a path containing a colon on a Unix-like platform results in an -/// error: -/// -/// ``` -/// # if cfg!(unix) { -/// use std::env; -/// use std::path::Path; -/// -/// let paths = [Path::new("/bin"), Path::new("/usr/bi:n")]; -/// assert!(env::join_paths(paths.iter()).is_err()); -/// # } -/// ``` -/// -/// Using `env::join_paths()` with [`env::split_paths()`] to append an item to -/// the `PATH` environment variable: -/// -/// ``` -/// use std::env; -/// use std::path::PathBuf; -/// -/// fn main() -> Result<(), env::JoinPathsError> { -/// if let Some(path) = env::var_os("PATH") { -/// let mut paths = env::split_paths(&path).collect::>(); -/// paths.push(PathBuf::from("/home/xyz/bin")); -/// let new_path = env::join_paths(paths)?; -/// unsafe { env::set_var("PATH", &new_path); } -/// } -/// -/// Ok(()) -/// } -/// ``` -/// -/// [`env::split_paths()`]: split_paths -#[stable(feature = "env", since = "1.0.0")] -pub fn join_paths(paths: I) -> Result -where - I: IntoIterator, - T: AsRef, -{ - os_imp::join_paths(paths.into_iter()).map_err(|e| JoinPathsError { inner: e }) -} - -#[stable(feature = "env", since = "1.0.0")] -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl Error for JoinPathsError { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - self.inner.description() - } -} - -/// Returns the path of the current user's home directory if known. -/// -/// This may return `None` if getting the directory fails or if the platform does not have user home directories. -/// -/// For storing user data and configuration it is often preferable to use more specific directories. -/// For example, [XDG Base Directories] on Unix or the `LOCALAPPDATA` and `APPDATA` environment variables on Windows. -/// -/// [XDG Base Directories]: https://specifications.freedesktop.org/basedir-spec/latest/ -/// -/// # Unix -/// -/// - Returns the value of the 'HOME' environment variable if it is set -/// (and not an empty string). -/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function -/// using the UID of the current user. An empty home directory field returned from the -/// `getpwuid_r` function is considered to be a valid value. -/// - Returns `None` if the current user has no entry in the /etc/passwd file. -/// -/// # Windows -/// -/// - Returns the value of the 'USERPROFILE' environment variable if it is set, and is not an empty string. -/// - Otherwise, [`GetUserProfileDirectory`][msdn] is used to return the path. This may change in the future. -/// -/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/userenv/nf-userenv-getuserprofiledirectorya -/// -/// In UWP (Universal Windows Platform) targets this function is unimplemented and always returns `None`. -/// -/// Before Rust 1.85.0, this function used to return the value of the 'HOME' environment variable -/// on Windows, which in Cygwin or Mingw environments could return non-standard paths like `/home/you` -/// instead of `C:\Users\you`. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// match env::home_dir() { -/// Some(path) => println!("Your home directory, probably: {}", path.display()), -/// None => println!("Impossible to get your home dir!"), -/// } -/// ``` -#[must_use] -#[stable(feature = "env", since = "1.0.0")] -pub fn home_dir() -> Option { - os_imp::home_dir() -} - -/// Returns the path of a temporary directory. -/// -/// The temporary directory may be shared among users, or between processes -/// with different privileges; thus, the creation of any files or directories -/// in the temporary directory must use a secure method to create a uniquely -/// named file. Creating a file or directory with a fixed or predictable name -/// may result in "insecure temporary file" security vulnerabilities. Consider -/// using a crate that securely creates temporary files or directories. -/// -/// Note that the returned value may be a symbolic link, not a directory. -/// -/// # Platform-specific behavior -/// -/// On Unix, returns the value of the `TMPDIR` environment variable if it is -/// set, otherwise the value is OS-specific: -/// - On Android, there is no global temporary folder (it is usually allocated -/// per-app), it will return the application's cache dir if the program runs -/// in application's namespace and system version is Android 13 (or above), or -/// `/data/local/tmp` otherwise. -/// - On Darwin-based OSes (macOS, iOS, etc) it returns the directory provided -/// by `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)`, as recommended by [Apple's -/// security guidelines][appledoc]. -/// - On all other unix-based OSes, it returns `/tmp`. -/// -/// 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]. -/// -/// [changes]: io#platform-specific-behavior -/// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a -/// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha -/// [appledoc]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 -/// -/// ```no_run -/// use std::env; -/// -/// fn main() { -/// let dir = env::temp_dir(); -/// println!("Temporary directory: {}", dir.display()); -/// } -/// ``` -#[must_use] -#[doc(alias = "GetTempPath", alias = "GetTempPath2")] -#[stable(feature = "env", since = "1.0.0")] -pub fn temp_dir() -> PathBuf { - os_imp::temp_dir() -} - -/// Returns the full filesystem path of the current running executable. -/// -/// # Platform-specific behavior -/// -/// If the executable was invoked through a symbolic link, some platforms will -/// return the path of the symbolic link and other platforms will return the -/// path of the symbolic link’s target. -/// -/// If the executable is renamed while it is running, platforms may return the -/// path at the time it was loaded instead of the new path. -/// -/// # Errors -/// -/// Acquiring the path of the current executable is a platform-specific operation -/// that can fail for a good number of reasons. Some errors can include, but not -/// be limited to, filesystem operations failing or general syscall failures. -/// -/// # Security -/// -/// The output of this function must be treated with care to avoid security -/// vulnerabilities, particularly in processes that run with privileges higher -/// than the user, such as setuid or setgid programs. -/// -/// For example, on some Unix platforms, the result is calculated by -/// searching `$PATH` for an executable matching `argv[0]`, but both the -/// environment and arguments can be be set arbitrarily by the user who -/// invokes the program. -/// -/// On Linux, if `fs.secure_hardlinks` is not set, an attacker who can -/// create hardlinks to the executable may be able to cause this function -/// to return an attacker-controlled path, which they later replace with -/// a different program. -/// -/// This list of illustrative example attacks is not exhaustive. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// match env::current_exe() { -/// Ok(exe_path) => println!("Path of this executable is: {}", -/// exe_path.display()), -/// Err(e) => println!("failed to get current exe path: {e}"), -/// }; -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn current_exe() -> io::Result { - os_imp::current_exe() -} - -/// An iterator over the arguments of a process, yielding a [`String`] value for -/// each argument. -/// -/// This struct is created by [`env::args()`]. See its documentation -/// for more. -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and might not even exist. This means this property -/// should not be relied upon for security purposes. -/// -/// [`env::args()`]: args -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "env", since = "1.0.0")] -pub struct Args { - inner: ArgsOs, -} - -/// An iterator over the arguments of a process, yielding an [`OsString`] value -/// for each argument. -/// -/// This struct is created by [`env::args_os()`]. See its documentation -/// for more. -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and might not even exist. This means this property -/// should not be relied upon for security purposes. -/// -/// [`env::args_os()`]: args_os -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "env", since = "1.0.0")] -pub struct ArgsOs { - inner: sys::args::Args, -} - -/// Returns the arguments that this program was started with (normally passed -/// via the command line). -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and might not even exist. This means this property should -/// not be relied upon for security purposes. -/// -/// On Unix systems the shell usually expands unquoted arguments with glob patterns -/// (such as `*` and `?`). On Windows this is not done, and such arguments are -/// passed as-is. -/// -/// On glibc Linux systems, arguments are retrieved by placing a function in `.init_array`. -/// glibc passes `argc`, `argv`, and `envp` to functions in `.init_array`, as a non-standard -/// extension. This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it -/// does on macOS and Windows. -/// -/// # Panics -/// -/// The returned iterator will panic during iteration if any argument to the -/// process is not valid Unicode. If this is not desired, -/// use the [`args_os`] function instead. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// // Prints each argument on a separate line -/// for argument in env::args() { -/// println!("{argument}"); -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn args() -> Args { - Args { inner: args_os() } -} - -/// Returns the arguments that this program was started with (normally passed -/// via the command line). -/// -/// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and might not even exist. This means this property should -/// not be relied upon for security purposes. -/// -/// On Unix systems the shell usually expands unquoted arguments with glob patterns -/// (such as `*` and `?`). On Windows this is not done, and such arguments are -/// passed as-is. -/// -/// On glibc Linux systems, arguments are retrieved by placing a function in `.init_array`. -/// glibc passes `argc`, `argv`, and `envp` to functions in `.init_array`, as a non-standard -/// extension. This allows `std::env::args_os` to work even in a `cdylib` or `staticlib`, as it -/// does on macOS and Windows. -/// -/// Note that the returned iterator will not check if the arguments to the -/// process are valid Unicode. If you want to panic on invalid UTF-8, -/// use the [`args`] function instead. -/// -/// # Examples -/// -/// ``` -/// use std::env; -/// -/// // Prints each argument on a separate line -/// for argument in env::args_os() { -/// println!("{argument:?}"); -/// } -/// ``` -#[stable(feature = "env", since = "1.0.0")] -pub fn args_os() -> ArgsOs { - ArgsOs { inner: sys::args::args() } -} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Send for Args {} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Sync for Args {} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for Args { - type Item = String; - - fn next(&mut self) -> Option { - self.inner.next().map(|s| s.into_string().unwrap()) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - // Methods which skip args cannot simply delegate to the inner iterator, - // because `env::args` states that we will "panic during iteration if any - // argument to the process is not valid Unicode". - // - // This offers two possible interpretations: - // - a skipped argument is never encountered "during iteration" - // - even a skipped argument is encountered "during iteration" - // - // As a panic can be observed, we err towards validating even skipped - // arguments for now, though this is not explicitly promised by the API. -} - -#[stable(feature = "env", since = "1.0.0")] -impl ExactSizeIterator for Args { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } - - #[inline] - fn is_empty(&self) -> bool { - self.inner.is_empty() - } -} - -#[stable(feature = "env_iterators", since = "1.12.0")] -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.inner.next_back().map(|s| s.into_string().unwrap()) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { inner: ArgsOs { inner } } = self; - f.debug_struct("Args").field("inner", inner).finish() - } -} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Send for ArgsOs {} - -#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] -impl !Sync for ArgsOs {} - -#[stable(feature = "env", since = "1.0.0")] -impl Iterator for ArgsOs { - type Item = OsString; - - #[inline] - fn next(&mut self) -> Option { - self.inner.next() - } - - #[inline] - fn next_chunk( - &mut self, - ) -> Result<[OsString; N], array::IntoIter> { - self.inner.next_chunk() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.inner.len() - } - - #[inline] - fn last(self) -> Option { - self.inner.last() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.inner.advance_by(n) - } - - #[inline] - fn try_fold(&mut self, init: B, f: F) -> R - where - F: FnMut(B, Self::Item) -> R, - R: Try, - { - self.inner.try_fold(init, f) - } - - #[inline] - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.inner.fold(init, f) - } -} - -#[stable(feature = "env", since = "1.0.0")] -impl ExactSizeIterator for ArgsOs { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } - - #[inline] - fn is_empty(&self) -> bool { - self.inner.is_empty() - } -} - -#[stable(feature = "env_iterators", since = "1.12.0")] -impl DoubleEndedIterator for ArgsOs { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.next_back() - } - - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.inner.advance_back_by(n) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ArgsOs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { inner } = self; - f.debug_struct("ArgsOs").field("inner", inner).finish() - } -} - -/// Constants associated with the current target -#[stable(feature = "env", since = "1.0.0")] -pub mod consts { - use crate::sys::env_consts::os; - - /// A string describing the architecture of the CPU that is currently in use. - /// An example value may be: `"x86"`, `"arm"` or `"riscv64"`. - /// - ///
Full list of possible values - /// - /// * `"x86"` - /// * `"x86_64"` - /// * `"arm"` - /// * `"aarch64"` - /// * `"m68k"` - /// * `"mips"` - /// * `"mips32r6"` - /// * `"mips64"` - /// * `"mips64r6"` - /// * `"csky"` - /// * `"powerpc"` - /// * `"powerpc64"` - /// * `"riscv32"` - /// * `"riscv64"` - /// * `"s390x"` - /// * `"sparc"` - /// * `"sparc64"` - /// * `"hexagon"` - /// * `"loongarch32"` - /// * `"loongarch64"` - /// - ///
- #[stable(feature = "env", since = "1.0.0")] - pub const ARCH: &str = env!("STD_ENV_ARCH"); - - /// A string describing the family of the operating system. - /// An example value may be: `"unix"`, or `"windows"`. - /// - /// This value may be an empty string if the family is unknown. - /// - ///
Full list of possible values - /// - /// * `"unix"` - /// * `"windows"` - /// * `"itron"` - /// * `"wasm"` - /// * `""` - /// - ///
- #[stable(feature = "env", since = "1.0.0")] - pub const FAMILY: &str = os::FAMILY; - - /// A string describing the specific operating system in use. - /// An example value may be: `"linux"`, or `"freebsd"`. - /// - ///
Full list of possible values - /// - /// * `"linux"` - /// * `"windows"` - /// * `"macos"` - /// * `"android"` - /// * `"ios"` - /// * `"openbsd"` - /// * `"freebsd"` - /// * `"netbsd"` - /// * `"wasi"` - /// * `"hermit"` - /// * `"aix"` - /// * `"apple"` - /// * `"dragonfly"` - /// * `"emscripten"` - /// * `"espidf"` - /// * `"fortanix"` - /// * `"uefi"` - /// * `"fuchsia"` - /// * `"haiku"` - /// * `"hermit"` - /// * `"watchos"` - /// * `"visionos"` - /// * `"tvos"` - /// * `"horizon"` - /// * `"hurd"` - /// * `"illumos"` - /// * `"l4re"` - /// * `"nto"` - /// * `"redox"` - /// * `"solaris"` - /// * `"solid_asp3"` - /// * `"vexos"` - /// * `"vita"` - /// * `"vxworks"` - /// * `"xous"` - /// - ///
- #[stable(feature = "env", since = "1.0.0")] - pub const OS: &str = os::OS; - - /// Specifies the filename prefix, if any, used for shared libraries on this platform. - /// This is either `"lib"` or an empty string. (`""`). - #[stable(feature = "env", since = "1.0.0")] - pub const DLL_PREFIX: &str = os::DLL_PREFIX; - - /// Specifies the filename suffix, if any, used for shared libraries on this platform. - /// An example value may be: `".so"`, `".elf"`, or `".dll"`. - /// - /// The possible values are identical to those of [`DLL_EXTENSION`], but with the leading period included. - #[stable(feature = "env", since = "1.0.0")] - pub const DLL_SUFFIX: &str = os::DLL_SUFFIX; - - /// Specifies the file extension, if any, used for shared libraries on this platform that goes after the dot. - /// An example value may be: `"so"`, `"elf"`, or `"dll"`. - /// - ///
Full list of possible values - /// - /// * `"so"` - /// * `"dylib"` - /// * `"dll"` - /// * `"sgxs"` - /// * `"a"` - /// * `"elf"` - /// * `"wasm"` - /// * `""` (an empty string) - /// - ///
- #[stable(feature = "env", since = "1.0.0")] - pub const DLL_EXTENSION: &str = os::DLL_EXTENSION; - - /// Specifies the filename suffix, if any, used for executable binaries on this platform. - /// An example value may be: `".exe"`, or `".efi"`. - /// - /// The possible values are identical to those of [`EXE_EXTENSION`], but with the leading period included. - #[stable(feature = "env", since = "1.0.0")] - pub const EXE_SUFFIX: &str = os::EXE_SUFFIX; - - /// Specifies the file extension, if any, used for executable binaries on this platform. - /// An example value may be: `"exe"`, or an empty string (`""`). - /// - ///
Full list of possible values - /// - /// * `"bin"` - /// * `"exe"` - /// * `"efi"` - /// * `"js"` - /// * `"sgxs"` - /// * `"elf"` - /// * `"wasm"` - /// * `""` (an empty string) - /// - ///
- #[stable(feature = "env", since = "1.0.0")] - pub const EXE_EXTENSION: &str = os::EXE_EXTENSION; -} diff --git a/library/std/src/env.rs b/library/std/src/env.rs new file mode 120000 index 0000000..d1f76a2 --- /dev/null +++ b/library/std/src/env.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/env.rs \ No newline at end of file diff --git a/library/std/src/error.rs b/library/std/src/error.rs deleted file mode 100644 index def5f98..0000000 --- a/library/std/src/error.rs +++ /dev/null @@ -1,562 +0,0 @@ -#![doc = include_str!("../../core/src/error.md")] -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::error::Error; -#[unstable(feature = "error_generic_member_access", issue = "99301")] -pub use core::error::{Request, request_ref, request_value}; - -use crate::backtrace::Backtrace; -use crate::fmt::{self, Write}; - -/// An error reporter that prints an error and its sources. -/// -/// Report also exposes configuration options for formatting the error sources, either entirely on a -/// single line, or in multi-line format with each source on a new line. -/// -/// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the -/// wrapped error be `Send`, `Sync`, or `'static`. -/// -/// # Examples -/// -/// ```rust -/// #![feature(error_reporter)] -/// use std::error::{Error, Report}; -/// use std::fmt; -/// -/// #[derive(Debug)] -/// struct SuperError { -/// source: SuperErrorSideKick, -/// } -/// -/// impl fmt::Display for SuperError { -/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperError is here!") -/// } -/// } -/// -/// impl Error for SuperError { -/// fn source(&self) -> Option<&(dyn Error + 'static)> { -/// Some(&self.source) -/// } -/// } -/// -/// #[derive(Debug)] -/// struct SuperErrorSideKick; -/// -/// impl fmt::Display for SuperErrorSideKick { -/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperErrorSideKick is here!") -/// } -/// } -/// -/// impl Error for SuperErrorSideKick {} -/// -/// fn get_super_error() -> Result<(), SuperError> { -/// Err(SuperError { source: SuperErrorSideKick }) -/// } -/// -/// fn main() { -/// match get_super_error() { -/// Err(e) => println!("Error: {}", Report::new(e)), -/// _ => println!("No error"), -/// } -/// } -/// ``` -/// -/// This example produces the following output: -/// -/// ```console -/// Error: SuperError is here!: SuperErrorSideKick is here! -/// ``` -/// -/// ## Output consistency -/// -/// Report prints the same output via `Display` and `Debug`, so it works well with -/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: -/// -/// ```should_panic -/// #![feature(error_reporter)] -/// use std::error::Report; -/// # use std::error::Error; -/// # use std::fmt; -/// # #[derive(Debug)] -/// # struct SuperError { -/// # source: SuperErrorSideKick, -/// # } -/// # impl fmt::Display for SuperError { -/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// # write!(f, "SuperError is here!") -/// # } -/// # } -/// # impl Error for SuperError { -/// # fn source(&self) -> Option<&(dyn Error + 'static)> { -/// # Some(&self.source) -/// # } -/// # } -/// # #[derive(Debug)] -/// # struct SuperErrorSideKick; -/// # impl fmt::Display for SuperErrorSideKick { -/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// # write!(f, "SuperErrorSideKick is here!") -/// # } -/// # } -/// # impl Error for SuperErrorSideKick {} -/// # fn get_super_error() -> Result<(), SuperError> { -/// # Err(SuperError { source: SuperErrorSideKick }) -/// # } -/// -/// get_super_error().map_err(Report::new).unwrap(); -/// ``` -/// -/// This example produces the following output: -/// -/// ```console -/// thread 'main' panicked at src/error.rs:34:40: -/// called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here! -/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -/// ``` -/// -/// ## Return from `main` -/// -/// `Report` also implements `From` for all types that implement [`Error`]; this when combined with -/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned -/// from `main`. -/// -/// ```should_panic -/// #![feature(error_reporter)] -/// use std::error::Report; -/// # use std::error::Error; -/// # use std::fmt; -/// # #[derive(Debug)] -/// # struct SuperError { -/// # source: SuperErrorSideKick, -/// # } -/// # impl fmt::Display for SuperError { -/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// # write!(f, "SuperError is here!") -/// # } -/// # } -/// # impl Error for SuperError { -/// # fn source(&self) -> Option<&(dyn Error + 'static)> { -/// # Some(&self.source) -/// # } -/// # } -/// # #[derive(Debug)] -/// # struct SuperErrorSideKick; -/// # impl fmt::Display for SuperErrorSideKick { -/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// # write!(f, "SuperErrorSideKick is here!") -/// # } -/// # } -/// # impl Error for SuperErrorSideKick {} -/// # fn get_super_error() -> Result<(), SuperError> { -/// # Err(SuperError { source: SuperErrorSideKick }) -/// # } -/// -/// fn main() -> Result<(), Report> { -/// get_super_error()?; -/// Ok(()) -/// } -/// ``` -/// -/// This example produces the following output: -/// -/// ```console -/// Error: SuperError is here!: SuperErrorSideKick is here! -/// ``` -/// -/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line -/// output format. If you want to make sure your `Report`s are pretty printed and include backtrace -/// you will need to manually convert and enable those flags. -/// -/// ```should_panic -/// #![feature(error_reporter)] -/// use std::error::Report; -/// # use std::error::Error; -/// # use std::fmt; -/// # #[derive(Debug)] -/// # struct SuperError { -/// # source: SuperErrorSideKick, -/// # } -/// # impl fmt::Display for SuperError { -/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// # write!(f, "SuperError is here!") -/// # } -/// # } -/// # impl Error for SuperError { -/// # fn source(&self) -> Option<&(dyn Error + 'static)> { -/// # Some(&self.source) -/// # } -/// # } -/// # #[derive(Debug)] -/// # struct SuperErrorSideKick; -/// # impl fmt::Display for SuperErrorSideKick { -/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// # write!(f, "SuperErrorSideKick is here!") -/// # } -/// # } -/// # impl Error for SuperErrorSideKick {} -/// # fn get_super_error() -> Result<(), SuperError> { -/// # Err(SuperError { source: SuperErrorSideKick }) -/// # } -/// -/// fn main() -> Result<(), Report> { -/// get_super_error() -/// .map_err(Report::from) -/// .map_err(|r| r.pretty(true).show_backtrace(true))?; -/// Ok(()) -/// } -/// ``` -/// -/// This example produces the following output: -/// -/// ```console -/// Error: SuperError is here! -/// -/// Caused by: -/// SuperErrorSideKick is here! -/// ``` -#[unstable(feature = "error_reporter", issue = "90172")] -pub struct Report> { - /// The error being reported. - error: E, - /// Whether a backtrace should be included as part of the report. - show_backtrace: bool, - /// Whether the report should be pretty-printed. - pretty: bool, -} - -impl Report -where - Report: From, -{ - /// Creates a new `Report` from an input error. - #[unstable(feature = "error_reporter", issue = "90172")] - pub fn new(error: E) -> Report { - Self::from(error) - } -} - -impl Report { - /// Enable pretty-printing the report across multiple lines. - /// - /// # Examples - /// - /// ```rust - /// #![feature(error_reporter)] - /// use std::error::Report; - /// # use std::error::Error; - /// # use std::fmt; - /// # #[derive(Debug)] - /// # struct SuperError { - /// # source: SuperErrorSideKick, - /// # } - /// # impl fmt::Display for SuperError { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperError is here!") - /// # } - /// # } - /// # impl Error for SuperError { - /// # fn source(&self) -> Option<&(dyn Error + 'static)> { - /// # Some(&self.source) - /// # } - /// # } - /// # #[derive(Debug)] - /// # struct SuperErrorSideKick; - /// # impl fmt::Display for SuperErrorSideKick { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperErrorSideKick is here!") - /// # } - /// # } - /// # impl Error for SuperErrorSideKick {} - /// - /// let error = SuperError { source: SuperErrorSideKick }; - /// let report = Report::new(error).pretty(true); - /// eprintln!("Error: {report:?}"); - /// ``` - /// - /// This example produces the following output: - /// - /// ```console - /// Error: SuperError is here! - /// - /// Caused by: - /// SuperErrorSideKick is here! - /// ``` - /// - /// When there are multiple source errors the causes will be numbered in order of iteration - /// starting from the outermost error. - /// - /// ```rust - /// #![feature(error_reporter)] - /// use std::error::Report; - /// # use std::error::Error; - /// # use std::fmt; - /// # #[derive(Debug)] - /// # struct SuperError { - /// # source: SuperErrorSideKick, - /// # } - /// # impl fmt::Display for SuperError { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperError is here!") - /// # } - /// # } - /// # impl Error for SuperError { - /// # fn source(&self) -> Option<&(dyn Error + 'static)> { - /// # Some(&self.source) - /// # } - /// # } - /// # #[derive(Debug)] - /// # struct SuperErrorSideKick { - /// # source: SuperErrorSideKickSideKick, - /// # } - /// # impl fmt::Display for SuperErrorSideKick { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperErrorSideKick is here!") - /// # } - /// # } - /// # impl Error for SuperErrorSideKick { - /// # fn source(&self) -> Option<&(dyn Error + 'static)> { - /// # Some(&self.source) - /// # } - /// # } - /// # #[derive(Debug)] - /// # struct SuperErrorSideKickSideKick; - /// # impl fmt::Display for SuperErrorSideKickSideKick { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperErrorSideKickSideKick is here!") - /// # } - /// # } - /// # impl Error for SuperErrorSideKickSideKick { } - /// - /// let source = SuperErrorSideKickSideKick; - /// let source = SuperErrorSideKick { source }; - /// let error = SuperError { source }; - /// let report = Report::new(error).pretty(true); - /// eprintln!("Error: {report:?}"); - /// ``` - /// - /// This example produces the following output: - /// - /// ```console - /// Error: SuperError is here! - /// - /// Caused by: - /// 0: SuperErrorSideKick is here! - /// 1: SuperErrorSideKickSideKick is here! - /// ``` - #[unstable(feature = "error_reporter", issue = "90172")] - pub fn pretty(mut self, pretty: bool) -> Self { - self.pretty = pretty; - self - } - - /// Display backtrace if available when using pretty output format. - /// - /// # Examples - /// - /// **Note**: Report will search for the first `Backtrace` it can find starting from the - /// outermost error. In this example it will display the backtrace from the second error in the - /// sources, `SuperErrorSideKick`. - /// - /// ```rust - /// #![feature(error_reporter)] - /// #![feature(error_generic_member_access)] - /// # use std::error::Error; - /// # use std::fmt; - /// use std::error::Request; - /// use std::error::Report; - /// use std::backtrace::Backtrace; - /// - /// # #[derive(Debug)] - /// # struct SuperError { - /// # source: SuperErrorSideKick, - /// # } - /// # impl fmt::Display for SuperError { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperError is here!") - /// # } - /// # } - /// # impl Error for SuperError { - /// # fn source(&self) -> Option<&(dyn Error + 'static)> { - /// # Some(&self.source) - /// # } - /// # } - /// #[derive(Debug)] - /// struct SuperErrorSideKick { - /// backtrace: Backtrace, - /// } - /// - /// impl SuperErrorSideKick { - /// fn new() -> SuperErrorSideKick { - /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } - /// } - /// } - /// - /// impl Error for SuperErrorSideKick { - /// fn provide<'a>(&'a self, request: &mut Request<'a>) { - /// request.provide_ref::(&self.backtrace); - /// } - /// } - /// - /// // The rest of the example is unchanged ... - /// # impl fmt::Display for SuperErrorSideKick { - /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// # write!(f, "SuperErrorSideKick is here!") - /// # } - /// # } - /// - /// let source = SuperErrorSideKick::new(); - /// let error = SuperError { source }; - /// let report = Report::new(error).pretty(true).show_backtrace(true); - /// eprintln!("Error: {report:?}"); - /// ``` - /// - /// This example produces something similar to the following output: - /// - /// ```console - /// Error: SuperError is here! - /// - /// Caused by: - /// SuperErrorSideKick is here! - /// - /// Stack backtrace: - /// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new - /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 - /// 2: rust_out::main - /// 3: core::ops::function::FnOnce::call_once - /// 4: std::sys::backtrace::__rust_begin_short_backtrace - /// 5: std::rt::lang_start::{{closure}} - /// 6: std::panicking::try - /// 7: std::rt::lang_start_internal - /// 8: std::rt::lang_start - /// 9: main - /// 10: __libc_start_main - /// 11: _start - /// ``` - #[unstable(feature = "error_reporter", issue = "90172")] - pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { - self.show_backtrace = show_backtrace; - self - } -} - -impl Report -where - E: Error, -{ - fn backtrace(&self) -> Option<&Backtrace> { - // have to grab the backtrace on the first error directly since that error may not be - // 'static - let backtrace = request_ref(&self.error); - let backtrace = backtrace.or_else(|| { - self.error - .source() - .map(|source| source.sources().find_map(|source| request_ref(source))) - .flatten() - }); - backtrace - } - - /// Format the report as a single line. - #[unstable(feature = "error_reporter", issue = "90172")] - fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.error)?; - - let sources = self.error.source().into_iter().flat_map(::sources); - - for cause in sources { - write!(f, ": {cause}")?; - } - - Ok(()) - } - - /// Format the report as multiple lines, with each error cause on its own line. - #[unstable(feature = "error_reporter", issue = "90172")] - fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let error = &self.error; - - write!(f, "{error}")?; - - if let Some(cause) = error.source() { - write!(f, "\n\nCaused by:")?; - - let multiple = cause.source().is_some(); - - for (ind, error) in cause.sources().enumerate() { - writeln!(f)?; - let mut indented = Indented { inner: f }; - if multiple { - write!(indented, "{ind: >4}: {error}")?; - } else { - write!(indented, " {error}")?; - } - } - } - - if self.show_backtrace { - if let Some(backtrace) = self.backtrace() { - write!(f, "\n\nStack backtrace:\n{}", backtrace.to_string().trim_end())?; - } - } - - Ok(()) - } -} - -#[unstable(feature = "error_reporter", issue = "90172")] -impl From for Report -where - E: Error, -{ - fn from(error: E) -> Self { - Report { error, show_backtrace: false, pretty: false } - } -} - -#[unstable(feature = "error_reporter", issue = "90172")] -impl fmt::Display for Report -where - E: Error, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } - } -} - -// This type intentionally outputs the same format for `Display` and `Debug`for -// situations where you unwrap a `Report` or return it from main. -#[unstable(feature = "error_reporter", issue = "90172")] -impl fmt::Debug for Report -where - Report: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -/// Wrapper type for indenting the inner source. -struct Indented<'a, D> { - inner: &'a mut D, -} - -impl Write for Indented<'_, T> -where - T: Write, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - for (i, line) in s.split('\n').enumerate() { - if i > 0 { - self.inner.write_char('\n')?; - self.inner.write_str(" ")?; - } - - self.inner.write_str(line)?; - } - - Ok(()) - } -} diff --git a/library/std/src/error.rs b/library/std/src/error.rs new file mode 120000 index 0000000..b4b0f08 --- /dev/null +++ b/library/std/src/error.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/error.rs \ No newline at end of file diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs deleted file mode 100644 index 885bf37..0000000 --- a/library/std/src/fs.rs +++ /dev/null @@ -1,3531 +0,0 @@ -//! Filesystem manipulation operations. -//! -//! This module contains basic methods to manipulate the contents of the local -//! filesystem. All methods in this module represent cross-platform filesystem -//! operations. Extra platform-specific functionality can be found in the -//! extension traits of `std::os::$platform`. -//! -//! # Time of Check to Time of Use (TOCTOU) -//! -//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use" -//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions) -//! and then uses the result of that check to make a decision, but the condition may have changed -//! between the check and the use. -//! -//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to -//! TOCTOU - another process could create the file between your check and creation attempt. -//! -//! Another example is with symbolic links: when removing a directory, if another process replaces -//! the directory with a symbolic link between the check and the removal operation, the removal -//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use -//! atomic operations to prevent such race conditions. -//! -//! To avoid TOCTOU issues: -//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by -//! changes made by other processes. -//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating). -//! - Keep file open for the duration of operations. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] - -#[cfg(all( - test, - not(any( - target_os = "emscripten", - target_os = "wasi", - target_env = "sgx", - target_os = "xous", - target_os = "trusty", - )) -))] -mod tests; - -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 crate::sync::Arc; -use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, fs as fs_imp}; -use crate::time::SystemTime; -use crate::{error, fmt}; - -/// An object providing access to an open file on the filesystem. -/// -/// An instance of a `File` can be read and/or written depending on what options -/// it was opened with. Files also implement [`Seek`] to alter the logical cursor -/// that the file contains internally. -/// -/// Files are automatically closed when they go out of scope. Errors detected -/// on closing are ignored by the implementation of `Drop`. Use the method -/// [`sync_all`] if these errors must be manually handled. -/// -/// `File` does not buffer reads and writes. For efficiency, consider wrapping the -/// file in a [`BufReader`] or [`BufWriter`] when performing many small [`read`] -/// or [`write`] calls, unless unbuffered reads and writes are required. -/// -/// # Examples -/// -/// Creates a new file and write bytes to it (you can also use [`write`]): -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut file = File::create("foo.txt")?; -/// file.write_all(b"Hello, world!")?; -/// Ok(()) -/// } -/// ``` -/// -/// Reads the contents of a file into a [`String`] (you can also use [`read`]): -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut file = File::open("foo.txt")?; -/// let mut contents = String::new(); -/// file.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// Ok(()) -/// } -/// ``` -/// -/// Using a buffered [`Read`]er: -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::BufReader; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let file = File::open("foo.txt")?; -/// let mut buf_reader = BufReader::new(file); -/// let mut contents = String::new(); -/// buf_reader.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// Ok(()) -/// } -/// ``` -/// -/// Note that, although read and write methods require a `&mut File`, because -/// of the interfaces for [`Read`] and [`Write`], the holder of a `&File` can -/// still modify the file, either through methods that take `&File` or by -/// retrieving the underlying OS object and modifying the file that way. -/// Additionally, many operating systems allow concurrent modification of files -/// by different processes. Avoid assuming that holding a `&File` means that the -/// file will not change. -/// -/// # Platform-specific behavior -/// -/// On Windows, the implementation of [`Read`] and [`Write`] traits for `File` -/// perform synchronous I/O operations. Therefore the underlying file must not -/// have been opened for asynchronous I/O (e.g. by using `FILE_FLAG_OVERLAPPED`). -/// -/// [`BufReader`]: io::BufReader -/// [`BufWriter`]: io::BufWriter -/// [`sync_all`]: File::sync_all -/// [`write`]: File::write -/// [`read`]: File::read -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "File")] -pub struct File { - inner: fs_imp::File, -} - -/// An enumeration of possible errors which can occur while trying to acquire a lock -/// from the [`try_lock`] method and [`try_lock_shared`] method on a [`File`]. -/// -/// [`try_lock`]: File::try_lock -/// [`try_lock_shared`]: File::try_lock_shared -#[stable(feature = "file_lock", since = "1.89.0")] -pub enum TryLockError { - /// The lock could not be acquired due to an I/O error on the file. The standard library will - /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] - /// - /// [`ErrorKind::WouldBlock`]: io::ErrorKind::WouldBlock - Error(io::Error), - /// The lock could not be acquired at this time because it is held by another handle/process. - WouldBlock, -} - -/// An object providing access to a directory on the filesystem. -/// -/// Directories are automatically closed when they go out of scope. Errors detected -/// on closing are ignored by the implementation of `Drop`. -/// -/// # Platform-specific behavior -/// -/// On supported systems (including Windows and some UNIX-based OSes), this function acquires a -/// handle/file descriptor for the directory. This allows functions like [`Dir::open_file`] to -/// avoid [TOCTOU] errors when the directory itself is being moved. -/// -/// On other systems, it stores an absolute path (see [`canonicalize()`]). In the latter case, no -/// [TOCTOU] guarantees are made. -/// -/// # Examples -/// -/// Opens a directory and then a file inside it. -/// -/// ```no_run -/// #![feature(dirfd)] -/// use std::{fs::Dir, io}; -/// -/// fn main() -> std::io::Result<()> { -/// let dir = Dir::open("foo")?; -/// let mut file = dir.open_file("bar.txt")?; -/// let contents = io::read_to_string(file)?; -/// assert_eq!(contents, "Hello, world!"); -/// Ok(()) -/// } -/// ``` -/// -/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou -#[unstable(feature = "dirfd", issue = "120426")] -pub struct Dir { - inner: fs_imp::Dir, -} - -/// Metadata information about a file. -/// -/// This structure is returned from the [`metadata`] or -/// [`symlink_metadata`] function or method and represents known -/// metadata about a file such as its permissions, size, modification -/// times, etc. -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Metadata(fs_imp::FileAttr); - -/// Iterator over the entries in a directory. -/// -/// This iterator is returned from the [`read_dir`] function of this module and -/// will yield instances of [io::Result]<[DirEntry]>. Through a [`DirEntry`] -/// information like the entry's path and possibly other metadata can be -/// learned. -/// -/// The order in which this iterator returns entries is platform and filesystem -/// dependent. -/// -/// # Errors -/// This [`io::Result`] will be an [`Err`] if an error occurred while fetching -/// the next entry from the OS. -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct ReadDir(fs_imp::ReadDir); - -/// Entries returned by the [`ReadDir`] iterator. -/// -/// An instance of `DirEntry` represents an entry inside of a directory on the -/// filesystem. Each entry can be inspected via methods to learn about the full -/// path or possibly other metadata through per-platform extension traits. -/// -/// # Platform-specific behavior -/// -/// On Unix, the `DirEntry` struct contains an internal reference to the open -/// directory. Holding `DirEntry` objects will consume a file handle even -/// after the `ReadDir` iterator is dropped. -/// -/// Note that this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -#[stable(feature = "rust1", since = "1.0.0")] -pub struct DirEntry(fs_imp::DirEntry); - -/// Options and flags which can be used to configure how a file is opened. -/// -/// This builder exposes the ability to configure how a [`File`] is opened and -/// what operations are permitted on the open file. The [`File::open`] and -/// [`File::create`] methods are aliases for commonly used options using this -/// builder. -/// -/// Generally speaking, when using `OpenOptions`, you'll first call -/// [`OpenOptions::new`], then chain calls to methods to set each option, then -/// call [`OpenOptions::open`], passing the path of the file you're trying to -/// open. This will give you a [`io::Result`] with a [`File`] inside that you -/// can further operate on. -/// -/// # Examples -/// -/// Opening a file to read: -/// -/// ```no_run -/// use std::fs::OpenOptions; -/// -/// let file = OpenOptions::new().read(true).open("foo.txt"); -/// ``` -/// -/// Opening a file for both reading and writing, as well as creating it if it -/// doesn't exist: -/// -/// ```no_run -/// use std::fs::OpenOptions; -/// -/// let file = OpenOptions::new() -/// .read(true) -/// .write(true) -/// .create(true) -/// .open("foo.txt"); -/// ``` -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "FsOpenOptions")] -pub struct OpenOptions(fs_imp::OpenOptions); - -/// Representation of the various timestamps on a file. -#[derive(Copy, Clone, Debug, Default)] -#[stable(feature = "file_set_times", since = "1.75.0")] -#[must_use = "must be applied to a file via `File::set_times` to have any effect"] -pub struct FileTimes(fs_imp::FileTimes); - -/// Representation of the various permissions on a file. -/// -/// This module only currently provides one bit of information, -/// [`Permissions::readonly`], which is exposed on all currently supported -/// platforms. Unix-specific functionality, such as mode bits, is available -/// through the [`PermissionsExt`] trait. -/// -/// [`PermissionsExt`]: crate::os::unix::fs::PermissionsExt -#[derive(Clone, PartialEq, Eq, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "FsPermissions")] -pub struct Permissions(fs_imp::FilePermissions); - -/// A structure representing a type of file with accessors for each file type. -/// It is returned by [`Metadata::file_type`] method. -#[stable(feature = "file_type", since = "1.1.0")] -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(not(test), rustc_diagnostic_item = "FileType")] -pub struct FileType(fs_imp::FileType); - -/// A builder used to create directories in various manners. -/// -/// This builder also supports platform-specific options. -#[stable(feature = "dir_builder", since = "1.6.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "DirBuilder")] -#[derive(Debug)] -pub struct DirBuilder { - inner: fs_imp::DirBuilder, - recursive: bool, -} - -/// Reads the entire contents of a file into a bytes vector. -/// -/// This is a convenience function for using [`File::open`] and [`read_to_end`] -/// with fewer imports and without an intermediate variable. -/// -/// [`read_to_end`]: Read::read_to_end -/// -/// # Errors -/// -/// This function will return an error if `path` does not already exist. -/// Other errors may also be returned according to [`OpenOptions::open`]. -/// -/// While reading from the file, this function handles [`io::ErrorKind::Interrupted`] -/// with automatic retries. See [io::Read] documentation for details. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> Result<(), Box> { -/// let data: Vec = fs::read("image.jpg")?; -/// assert_eq!(data[0..3], [0xFF, 0xD8, 0xFF]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] -pub fn read>(path: P) -> io::Result> { - fn inner(path: &Path) -> io::Result> { - let mut file = File::open(path)?; - let size = file.metadata().map(|m| usize::try_from(m.len()).unwrap_or(usize::MAX)).ok(); - let mut bytes = Vec::try_with_capacity(size.unwrap_or(0))?; - io::default_read_to_end(&mut file, &mut bytes, size)?; - Ok(bytes) - } - inner(path.as_ref()) -} - -/// Reads the entire contents of a file into a string. -/// -/// This is a convenience function for using [`File::open`] and [`read_to_string`] -/// with fewer imports and without an intermediate variable. -/// -/// [`read_to_string`]: Read::read_to_string -/// -/// # Errors -/// -/// This function will return an error if `path` does not already exist. -/// Other errors may also be returned according to [`OpenOptions::open`]. -/// -/// If the contents of the file are not valid UTF-8, then an error will also be -/// returned. -/// -/// While reading from the file, this function handles [`io::ErrorKind::Interrupted`] -/// with automatic retries. See [io::Read] documentation for details. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// use std::error::Error; -/// -/// fn main() -> Result<(), Box> { -/// let message: String = fs::read_to_string("message.txt")?; -/// println!("{}", message); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_read_write", since = "1.26.0")] -pub fn read_to_string>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - let mut file = File::open(path)?; - let size = file.metadata().map(|m| usize::try_from(m.len()).unwrap_or(usize::MAX)).ok(); - let mut string = String::new(); - string.try_reserve_exact(size.unwrap_or(0))?; - io::default_read_to_string(&mut file, &mut string, size)?; - Ok(string) - } - inner(path.as_ref()) -} - -/// Writes a slice as the entire contents of a file. -/// -/// This function will create a file if it does not exist, -/// and will entirely replace its contents if it does. -/// -/// Depending on the platform, this function may fail if the -/// full directory path does not exist. -/// -/// This is a convenience function for using [`File::create`] and [`write_all`] -/// with fewer imports. -/// -/// [`write_all`]: Write::write_all -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::write("foo.txt", b"Lorem ipsum")?; -/// fs::write("bar.txt", "dolor sit")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] -pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { - fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { - File::create(path)?.write_all(contents) - } - inner(path.as_ref(), contents.as_ref()) -} - -/// Changes the timestamps of the file or directory at the specified path. -/// -/// This function will attempt to set the access and modification times -/// to the times specified. If the path refers to a symbolic link, this function -/// will follow the link and change the timestamps of the target file. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `utimensat` function on Unix platforms, the -/// `setattrlist` function on Apple platforms, and the `SetFileTime` function on Windows. -/// -/// # Errors -/// -/// This function will return an error if the user lacks permission to change timestamps on the -/// target file or symlink. It may also return an error if the OS does not support it. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(fs_set_times)] -/// use std::fs::{self, FileTimes}; -/// use std::time::SystemTime; -/// -/// fn main() -> std::io::Result<()> { -/// let now = SystemTime::now(); -/// let times = FileTimes::new() -/// .set_accessed(now) -/// .set_modified(now); -/// fs::set_times("foo.txt", times)?; -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "fs_set_times", issue = "147455")] -#[doc(alias = "utimens")] -#[doc(alias = "utimes")] -#[doc(alias = "utime")] -pub fn set_times>(path: P, times: FileTimes) -> io::Result<()> { - fs_imp::set_times(path.as_ref(), times.0) -} - -/// Changes the timestamps of the file or symlink at the specified path. -/// -/// This function will attempt to set the access and modification times -/// to the times specified. Differ from `set_times`, if the path refers to a symbolic link, -/// this function will change the timestamps of the symlink itself, not the target file. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `utimensat` function with `AT_SYMLINK_NOFOLLOW` on -/// Unix platforms, the `setattrlist` function with `FSOPT_NOFOLLOW` on Apple platforms, and the -/// `SetFileTime` function on Windows. -/// -/// # Errors -/// -/// This function will return an error if the user lacks permission to change timestamps on the -/// target file or symlink. It may also return an error if the OS does not support it. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(fs_set_times)] -/// use std::fs::{self, FileTimes}; -/// use std::time::SystemTime; -/// -/// fn main() -> std::io::Result<()> { -/// let now = SystemTime::now(); -/// let times = FileTimes::new() -/// .set_accessed(now) -/// .set_modified(now); -/// fs::set_times_nofollow("symlink.txt", times)?; -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "fs_set_times", issue = "147455")] -#[doc(alias = "utimensat")] -#[doc(alias = "lutimens")] -#[doc(alias = "lutimes")] -pub fn set_times_nofollow>(path: P, times: FileTimes) -> io::Result<()> { - fs_imp::set_times_nofollow(path.as_ref(), times.0) -} - -#[stable(feature = "file_lock", since = "1.89.0")] -impl error::Error for TryLockError {} - -#[stable(feature = "file_lock", since = "1.89.0")] -impl fmt::Debug for TryLockError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TryLockError::Error(err) => err.fmt(f), - TryLockError::WouldBlock => "WouldBlock".fmt(f), - } - } -} - -#[stable(feature = "file_lock", since = "1.89.0")] -impl fmt::Display for TryLockError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - TryLockError::Error(_) => "lock acquisition failed due to I/O error", - TryLockError::WouldBlock => "lock acquisition failed because the operation would block", - } - .fmt(f) - } -} - -#[stable(feature = "file_lock", since = "1.89.0")] -impl From for io::Error { - fn from(err: TryLockError) -> io::Error { - match err { - TryLockError::Error(err) => err, - TryLockError::WouldBlock => io::ErrorKind::WouldBlock.into(), - } - } -} - -impl File { - /// Attempts to open a file in read-only mode. - /// - /// See the [`OpenOptions::open`] method for more details. - /// - /// If you only need to read the entire file contents, - /// consider [`std::fs::read()`][self::read] or - /// [`std::fs::read_to_string()`][self::read_to_string] instead. - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::Read; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut data = vec![]; - /// f.read_to_end(&mut data)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn open>(path: P) -> io::Result { - OpenOptions::new().read(true).open(path.as_ref()) - } - - /// Attempts to open a file in read-only mode with buffering. - /// - /// See the [`OpenOptions::open`] method, the [`BufReader`][io::BufReader] type, - /// and the [`BufRead`][io::BufRead] trait for more details. - /// - /// If you only need to read the entire file contents, - /// consider [`std::fs::read()`][self::read] or - /// [`std::fs::read_to_string()`][self::read_to_string] instead. - /// - /// # Errors - /// - /// This function will return an error if `path` does not already exist, - /// or if memory allocation fails for the new buffer. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(file_buffered)] - /// use std::fs::File; - /// use std::io::BufRead; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::open_buffered("foo.txt")?; - /// assert!(f.capacity() > 0); - /// for (line, i) in f.lines().zip(1..) { - /// println!("{i:6}: {}", line?); - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "file_buffered", issue = "130804")] - pub fn open_buffered>(path: P) -> io::Result> { - // Allocate the buffer *first* so we don't affect the filesystem otherwise. - let buffer = io::BufReader::::try_new_buffer()?; - let file = File::open(path)?; - Ok(io::BufReader::with_buffer(file, buffer)) - } - - /// Opens a file in write-only mode. - /// - /// This function will create a file if it does not exist, - /// and will truncate it if it does. - /// - /// Depending on the platform, this function may fail if the - /// full directory path does not exist. - /// See the [`OpenOptions::open`] function for more details. - /// - /// See also [`std::fs::write()`][self::write] for a simple function to - /// create a file with some given data. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::Write; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(&1234_u32.to_be_bytes())?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn create>(path: P) -> io::Result { - OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) - } - - /// Opens a file in write-only mode with buffering. - /// - /// This function will create a file if it does not exist, - /// and will truncate it if it does. - /// - /// Depending on the platform, this function may fail if the - /// full directory path does not exist. - /// - /// See the [`OpenOptions::open`] method and the - /// [`BufWriter`][io::BufWriter] type for more details. - /// - /// See also [`std::fs::write()`][self::write] for a simple function to - /// create a file with some given data. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(file_buffered)] - /// use std::fs::File; - /// use std::io::Write; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create_buffered("foo.txt")?; - /// assert!(f.capacity() > 0); - /// for i in 0..100 { - /// writeln!(&mut f, "{i}")?; - /// } - /// f.flush()?; - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "file_buffered", issue = "130804")] - pub fn create_buffered>(path: P) -> io::Result> { - // Allocate the buffer *first* so we don't affect the filesystem otherwise. - let buffer = io::BufWriter::::try_new_buffer()?; - let file = File::create(path)?; - Ok(io::BufWriter::with_buffer(file, buffer)) - } - - /// Creates a new file in read-write mode; error if the file exists. - /// - /// This function will create a file if it does not exist, or return an error if it does. This - /// way, if the call succeeds, the file returned is guaranteed to be new. - /// If a file exists at the target location, creating a new file will fail with [`AlreadyExists`] - /// or another error based on the situation. See [`OpenOptions::open`] for a - /// non-exhaustive list of likely errors. - /// - /// This option is useful because it is atomic. Otherwise between checking whether a file - /// exists and creating a new one, the file may have been created by another process (a [TOCTOU] - /// race condition / attack). - /// - /// This can also be written using - /// `File::options().read(true).write(true).create_new(true).open(...)`. - /// - /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists - /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::Write; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create_new("foo.txt")?; - /// f.write_all("Hello, world!".as_bytes())?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_create_new", since = "1.77.0")] - pub fn create_new>(path: P) -> io::Result { - OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref()) - } - - /// Returns a new OpenOptions object. - /// - /// This function returns a new OpenOptions object that you can use to - /// open or create a file with specific options if `open()` or `create()` - /// are not appropriate. - /// - /// It is equivalent to `OpenOptions::new()`, but allows you to write more - /// readable code. Instead of - /// `OpenOptions::new().append(true).open("example.log")`, - /// you can write `File::options().append(true).open("example.log")`. This - /// also avoids the need to import `OpenOptions`. - /// - /// See the [`OpenOptions::new`] function for more details. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::Write; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::options().append(true).open("example.log")?; - /// writeln!(&mut f, "new line")?; - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "with_options", since = "1.58.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "file_options")] - pub fn options() -> OpenOptions { - OpenOptions::new() - } - - /// Attempts to sync all OS-internal file content and metadata to disk. - /// - /// This function will attempt to ensure that all in-memory data reaches the - /// filesystem before returning. - /// - /// This can be used to handle errors that would otherwise only be caught - /// when the `File` is closed, as dropping a `File` will ignore all errors. - /// Note, however, that `sync_all` is generally more expensive than closing - /// a file by dropping it, because the latter is not required to block until - /// the data has been written to the filesystem. - /// - /// If synchronizing the metadata is not required, use [`sync_data`] instead. - /// - /// [`sync_data`]: File::sync_data - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; - /// - /// f.sync_all()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[doc(alias = "fsync")] - pub fn sync_all(&self) -> io::Result<()> { - self.inner.fsync() - } - - /// This function is similar to [`sync_all`], except that it might not - /// synchronize file metadata to the filesystem. - /// - /// This is intended for use cases that must synchronize content, but don't - /// need the metadata on disk. The goal of this method is to reduce disk - /// operations. - /// - /// Note that some platforms may simply implement this in terms of - /// [`sync_all`]. - /// - /// [`sync_all`]: File::sync_all - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; - /// - /// f.sync_data()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[doc(alias = "fdatasync")] - pub fn sync_data(&self) -> io::Result<()> { - self.inner.datasync() - } - - /// Acquire an exclusive lock on the file. Blocks until the lock can be acquired. - /// - /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. - /// - /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], - /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with - /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not - /// cause non-lockholders to block. - /// - /// If this file handle/descriptor, or a clone of it, already holds a lock the exact behavior - /// is unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. - /// - /// If the file is not open for writing, it is unspecified whether this function returns an error. - /// - /// The lock will be released when this file (along with any other file descriptors/handles - /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag, - /// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that, - /// this [may change in the future][changes]. - /// - /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, - /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. - /// - /// [changes]: io#platform-specific-behavior - /// - /// [`lock`]: File::lock - /// [`lock_shared`]: File::lock_shared - /// [`try_lock`]: File::try_lock - /// [`try_lock_shared`]: File::try_lock_shared - /// [`unlock`]: File::unlock - /// [`read`]: Read::read - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// f.lock()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_lock", since = "1.89.0")] - pub fn lock(&self) -> io::Result<()> { - self.inner.lock() - } - - /// Acquire a shared (non-exclusive) lock on the file. Blocks until the lock can be acquired. - /// - /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may - /// hold an exclusive lock at the same time. - /// - /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], - /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with - /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not - /// cause non-lockholders to block. - /// - /// If this file handle/descriptor, or a clone of it, already holds a lock, the exact behavior - /// is unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. - /// - /// The lock will be released when this file (along with any other file descriptors/handles - /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag, - /// and the `LockFileEx` function on Windows. Note that, this - /// [may change in the future][changes]. - /// - /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, - /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. - /// - /// [changes]: io#platform-specific-behavior - /// - /// [`lock`]: File::lock - /// [`lock_shared`]: File::lock_shared - /// [`try_lock`]: File::try_lock - /// [`try_lock_shared`]: File::try_lock_shared - /// [`unlock`]: File::unlock - /// [`read`]: Read::read - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; - /// f.lock_shared()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_lock", since = "1.89.0")] - pub fn lock_shared(&self) -> io::Result<()> { - self.inner.lock_shared() - } - - /// Try to acquire an exclusive lock on the file. - /// - /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file - /// (via another handle/descriptor). - /// - /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. - /// - /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], - /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with - /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not - /// cause non-lockholders to block. - /// - /// If this file handle/descriptor, or a clone of it, already holds a lock, the exact behavior - /// is unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns `Ok(())`, then it has acquired an exclusive lock. - /// - /// If the file is not open for writing, it is unspecified whether this function returns an error. - /// - /// The lock will be released when this file (along with any other file descriptors/handles - /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and - /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` - /// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this - /// [may change in the future][changes]. - /// - /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, - /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. - /// - /// [changes]: io#platform-specific-behavior - /// - /// [`lock`]: File::lock - /// [`lock_shared`]: File::lock_shared - /// [`try_lock`]: File::try_lock - /// [`try_lock_shared`]: File::try_lock_shared - /// [`unlock`]: File::unlock - /// [`read`]: Read::read - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::{File, TryLockError}; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// // Explicit handling of the WouldBlock error - /// match f.try_lock() { - /// Ok(_) => (), - /// Err(TryLockError::WouldBlock) => (), // Lock not acquired - /// Err(TryLockError::Error(err)) => return Err(err), - /// } - /// // Alternately, propagate the error as an io::Error - /// f.try_lock()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_lock", since = "1.89.0")] - pub fn try_lock(&self) -> Result<(), TryLockError> { - self.inner.try_lock() - } - - /// Try to acquire a shared (non-exclusive) lock on the file. - /// - /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file - /// (via another handle/descriptor). - /// - /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may - /// hold an exclusive lock at the same time. - /// - /// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`], - /// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with - /// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not - /// cause non-lockholders to block. - /// - /// If this file handle, or a clone of it, already holds a lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns `Ok(())`, then it has acquired a shared lock. - /// - /// The lock will be released when this file (along with any other file descriptors/handles - /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and - /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the - /// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this - /// [may change in the future][changes]. - /// - /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, - /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. - /// - /// [changes]: io#platform-specific-behavior - /// - /// [`lock`]: File::lock - /// [`lock_shared`]: File::lock_shared - /// [`try_lock`]: File::try_lock - /// [`try_lock_shared`]: File::try_lock_shared - /// [`unlock`]: File::unlock - /// [`read`]: Read::read - /// [`write`]: Write::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::{File, TryLockError}; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; - /// // Explicit handling of the WouldBlock error - /// match f.try_lock_shared() { - /// Ok(_) => (), - /// Err(TryLockError::WouldBlock) => (), // Lock not acquired - /// Err(TryLockError::Error(err)) => return Err(err), - /// } - /// // Alternately, propagate the error as an io::Error - /// f.try_lock_shared()?; - /// - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_lock", since = "1.89.0")] - pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - self.inner.try_lock_shared() - } - - /// Release all locks on the file. - /// - /// All locks are released when the file (along with any other file descriptors/handles - /// duplicated or inherited from it) is closed. This method allows releasing locks without - /// closing the file. - /// - /// If no lock is currently held via this file descriptor/handle, this method may return an - /// error, or may return successfully without taking any action. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `flock` function on Unix with the `LOCK_UN` flag, - /// and the `UnlockFile` function on Windows. Note that, this - /// [may change in the future][changes]. - /// - /// On Windows, locking a file will fail if the file is opened only for append. To lock a file, - /// open it with one of `.read(true)`, `.read(true).append(true)`, or `.write(true)`. - /// - /// [changes]: io#platform-specific-behavior - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; - /// f.lock()?; - /// f.unlock()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_lock", since = "1.89.0")] - pub fn unlock(&self) -> io::Result<()> { - self.inner.unlock() - } - - /// Truncates or extends the underlying file, updating the size of - /// this file to become `size`. - /// - /// If the `size` is less than the current file's size, then the file will - /// be shrunk. If it is greater than the current file's size, then the file - /// will be extended to `size` and have all of the intermediate data filled - /// in with 0s. - /// - /// The file's cursor isn't changed. In particular, if the cursor was at the - /// end and the file is shrunk using this operation, the cursor will now be - /// past the end. - /// - /// # Errors - /// - /// This function will return an error if the file is not opened for writing. - /// Also, [`std::io::ErrorKind::InvalidInput`](crate::io::ErrorKind::InvalidInput) - /// will be returned if the desired length would cause an overflow due to - /// the implementation specifics. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.set_len(10)?; - /// Ok(()) - /// } - /// ``` - /// - /// Note that this method alters the content of the underlying file, even - /// though it takes `&self` rather than `&mut self`. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_len(&self, size: u64) -> io::Result<()> { - self.inner.truncate(size) - } - - /// Queries metadata about the underlying file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let metadata = f.metadata()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn metadata(&self) -> io::Result { - self.inner.file_attr().map(Metadata) - } - - /// Creates a new `File` instance that shares the same underlying file handle - /// as the existing `File` instance. Reads, writes, and seeks will affect - /// both `File` instances simultaneously. - /// - /// # Examples - /// - /// Creates two handles for a file named `foo.txt`: - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let file_copy = file.try_clone()?; - /// Ok(()) - /// } - /// ``` - /// - /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create - /// two handles, seek one of them, and read the remaining bytes from the - /// other handle: - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::SeekFrom; - /// use std::io::prelude::*; - /// - /// fn main() -> std::io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let mut file_copy = file.try_clone()?; - /// - /// file.seek(SeekFrom::Start(3))?; - /// - /// let mut contents = vec![]; - /// file_copy.read_to_end(&mut contents)?; - /// assert_eq!(contents, b"def\n"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_try_clone", since = "1.9.0")] - pub fn try_clone(&self) -> io::Result { - Ok(File { inner: self.inner.duplicate()? }) - } - - /// Changes the permissions on the underlying file. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `fchmod` function on Unix and - /// the `SetFileInformationByHandle` function on Windows. Note that, this - /// [may change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - /// - /// # Errors - /// - /// This function will return an error if the user lacks permission change - /// attributes on the underlying file. It may also return an error in other - /// os-specific unspecified cases. - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs::File; - /// - /// let file = File::open("foo.txt")?; - /// let mut perms = file.metadata()?.permissions(); - /// perms.set_readonly(true); - /// file.set_permissions(perms)?; - /// Ok(()) - /// } - /// ``` - /// - /// Note that this method alters the permissions of the underlying file, - /// even though it takes `&self` rather than `&mut self`. - #[doc(alias = "fchmod", alias = "SetFileInformationByHandle")] - #[stable(feature = "set_permissions_atomic", since = "1.16.0")] - pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { - self.inner.set_permissions(perm.0) - } - - /// Changes the timestamps of the underlying file. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `futimens` function on Unix (falling back to - /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this - /// [may change in the future][changes]. - /// - /// On most platforms, including UNIX and Windows platforms, this function can also change the - /// timestamps of a directory. To get a `File` representing a directory in order to call - /// `set_times`, open the directory with `File::open` without attempting to obtain write - /// permission. - /// - /// [changes]: io#platform-specific-behavior - /// - /// # Errors - /// - /// This function will return an error if the user lacks permission to change timestamps on the - /// underlying file. It may also return an error in other os-specific unspecified cases. - /// - /// This function may return an error if the operating system lacks support to change one or - /// more of the timestamps set in the `FileTimes` structure. - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs::{self, File, FileTimes}; - /// - /// let src = fs::metadata("src")?; - /// let dest = File::open("dest")?; - /// let times = FileTimes::new() - /// .set_accessed(src.accessed()?) - /// .set_modified(src.modified()?); - /// dest.set_times(times)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_set_times", since = "1.75.0")] - #[doc(alias = "futimens")] - #[doc(alias = "futimes")] - #[doc(alias = "SetFileTime")] - pub fn set_times(&self, times: FileTimes) -> io::Result<()> { - self.inner.set_times(times.0) - } - - /// Changes the modification time of the underlying file. - /// - /// This is an alias for `set_times(FileTimes::new().set_modified(time))`. - #[stable(feature = "file_set_times", since = "1.75.0")] - #[inline] - pub fn set_modified(&self, time: SystemTime) -> io::Result<()> { - self.set_times(FileTimes::new().set_modified(time)) - } -} - -// In addition to the `impl`s here, `File` also has `impl`s for -// `AsFd`/`From`/`Into` and -// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and -// `AsHandle`/`From`/`Into` and -// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. - -impl AsInner for File { - #[inline] - fn as_inner(&self) -> &fs_imp::File { - &self.inner - } -} -impl FromInner for File { - fn from_inner(f: fs_imp::File) -> File { - File { inner: f } - } -} -impl IntoInner for File { - fn into_inner(self) -> fs_imp::File { - self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -/// Indicates how much extra capacity is needed to read the rest of the file. -fn buffer_capacity_required(mut file: &File) -> Option { - let size = file.metadata().map(|m| m.len()).ok()?; - let pos = file.stream_position().ok()?; - // Don't worry about `usize` overflow because reading will fail regardless - // in that case. - Some(size.saturating_sub(pos) as usize) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for &File { - /// Reads some bytes from the file. - /// - /// See [`Read::read`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `read` function on Unix and - /// the `NtReadFile` function on Windows. Note that this [may change in - /// the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - /// Like `read`, except that it reads into a slice of buffers. - /// - /// See [`Read::read_vectored`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `readv` function on Unix and - /// falls back to the `read` implementation on Windows. Note that this - /// [may change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - #[inline] - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.inner.read_vectored(bufs) - } - - #[inline] - fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.inner.read_buf(cursor) - } - - /// Determines if `File` has an efficient `read_vectored` implementation. - /// - /// See [`Read::is_read_vectored`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently returns `true` on Unix and `false` on Windows. - /// Note that this [may change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - #[inline] - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - // Reserves space in the buffer based on the file size when available. - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - let size = buffer_capacity_required(self); - buf.try_reserve(size.unwrap_or(0))?; - io::default_read_to_end(self, buf, size) - } - - // Reserves space in the buffer based on the file size when available. - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - let size = buffer_capacity_required(self); - buf.try_reserve(size.unwrap_or(0))?; - io::default_read_to_string(self, buf, size) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for &File { - /// Writes some bytes to the file. - /// - /// See [`Write::write`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `write` function on Unix and - /// the `NtWriteFile` function on Windows. Note that this [may change in - /// the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - - /// Like `write`, except that it writes into a slice of buffers. - /// - /// See [`Write::write_vectored`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `writev` function on Unix - /// and falls back to the `write` implementation on Windows. Note that this - /// [may change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.write_vectored(bufs) - } - - /// Determines if `File` has an efficient `write_vectored` implementation. - /// - /// See [`Write::is_write_vectored`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently returns `true` on Unix and `false` on Windows. - /// Note that this [may change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - #[inline] - fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() - } - - /// Flushes the file, ensuring that all intermediately buffered contents - /// reach their destination. - /// - /// See [`Write::flush`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// Since a `File` structure doesn't contain any buffers, this function is - /// currently a no-op on Unix and Windows. Note that this [may change in - /// the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - #[inline] - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for &File { - /// Seek to an offset, in bytes in a file. - /// - /// See [`Seek::seek`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `lseek64` function on Unix - /// and the `SetFilePointerEx` function on Windows. Note that this [may - /// change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.inner.seek(pos) - } - - /// Returns the length of this file (in bytes). - /// - /// See [`Seek::stream_len`] docs for more info. - /// - /// # Platform-specific behavior - /// - /// This function currently corresponds to the `statx` function on Linux - /// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that - /// this [may change in the future][changes]. - /// - /// [changes]: io#platform-specific-behavior - fn stream_len(&mut self) -> io::Result { - if let Some(result) = self.inner.size() { - return result; - } - io::stream_len_default(self) - } - - fn stream_position(&mut self) -> io::Result { - self.inner.tell() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Read for File { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (&*self).read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - (&*self).read_vectored(bufs) - } - fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - (&*self).read_buf(cursor) - } - #[inline] - fn is_read_vectored(&self) -> bool { - (&&*self).is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (&*self).read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (&*self).read_to_string(buf) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Write for File { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&*self).write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&*self).write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - (&&*self).is_write_vectored() - } - #[inline] - fn flush(&mut self) -> io::Result<()> { - (&*self).flush() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Seek for File { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - (&*self).seek(pos) - } - fn stream_len(&mut self) -> io::Result { - (&*self).stream_len() - } - fn stream_position(&mut self) -> io::Result { - (&*self).stream_position() - } -} - -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Read for Arc { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (&**self).read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - (&**self).read_vectored(bufs) - } - fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - (&**self).read_buf(cursor) - } - #[inline] - fn is_read_vectored(&self) -> bool { - (&**self).is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (&**self).read_to_end(buf) - } - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (&**self).read_to_string(buf) - } -} -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Write for Arc { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&**self).write(buf) - } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&**self).write_vectored(bufs) - } - #[inline] - fn is_write_vectored(&self) -> bool { - (&**self).is_write_vectored() - } - #[inline] - fn flush(&mut self) -> io::Result<()> { - (&**self).flush() - } -} -#[stable(feature = "io_traits_arc", since = "1.73.0")] -impl Seek for Arc { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - (&**self).seek(pos) - } - fn stream_len(&mut self) -> io::Result { - (&**self).stream_len() - } - fn stream_position(&mut self) -> io::Result { - (&**self).stream_position() - } -} - -impl Dir { - /// Attempts to open a directory at `path` in read-only mode. - /// - /// # Errors - /// - /// This function will return an error if `path` does not point to an existing directory. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(dirfd)] - /// use std::{fs::Dir, io}; - /// - /// fn main() -> std::io::Result<()> { - /// let dir = Dir::open("foo")?; - /// let mut f = dir.open_file("bar.txt")?; - /// let contents = io::read_to_string(f)?; - /// assert_eq!(contents, "Hello, world!"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "dirfd", issue = "120426")] - pub fn open>(path: P) -> io::Result { - fs_imp::Dir::open(path.as_ref(), &OpenOptions::new().read(true).0) - .map(|inner| Self { inner }) - } - - /// Attempts to open a file in read-only mode relative to this directory. - /// - /// # Errors - /// - /// This function will return an error if `path` does not point to an existing file. - /// Other errors may also be returned according to [`OpenOptions::open`]. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(dirfd)] - /// use std::{fs::Dir, io}; - /// - /// fn main() -> std::io::Result<()> { - /// let dir = Dir::open("foo")?; - /// let mut f = dir.open_file("bar.txt")?; - /// let contents = io::read_to_string(f)?; - /// assert_eq!(contents, "Hello, world!"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "dirfd", issue = "120426")] - pub fn open_file>(&self, path: P) -> io::Result { - self.inner - .open_file(path.as_ref(), &OpenOptions::new().read(true).0) - .map(|f| File { inner: f }) - } -} - -impl AsInner for Dir { - #[inline] - fn as_inner(&self) -> &fs_imp::Dir { - &self.inner - } -} -impl FromInner for Dir { - fn from_inner(f: fs_imp::Dir) -> Dir { - Dir { inner: f } - } -} -impl IntoInner for Dir { - fn into_inner(self) -> fs_imp::Dir { - self.inner - } -} - -#[unstable(feature = "dirfd", issue = "120426")] -impl fmt::Debug for Dir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl OpenOptions { - /// Creates a blank new set of options ready for configuration. - /// - /// All options are initially set to `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let mut options = OpenOptions::new(); - /// let file = options.read(true).open("foo.txt"); - /// ``` - #[cfg_attr(not(test), rustc_diagnostic_item = "open_options_new")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn new() -> Self { - OpenOptions(fs_imp::OpenOptions::new()) - } - - /// Sets the option for read access. - /// - /// This option, when true, will indicate that the file should be - /// `read`-able if opened. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().read(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn read(&mut self, read: bool) -> &mut Self { - self.0.read(read); - self - } - - /// Sets the option for write access. - /// - /// This option, when true, will indicate that the file should be - /// `write`-able if opened. - /// - /// If the file already exists, any write calls on it will overwrite its - /// contents, without truncating it. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn write(&mut self, write: bool) -> &mut Self { - self.0.write(write); - self - } - - /// Sets the option for the append mode. - /// - /// This option, when true, means that writes will append to a file instead - /// of overwriting previous contents. - /// Note that setting `.write(true).append(true)` has the same effect as - /// setting only `.append(true)`. - /// - /// Append mode guarantees that writes will be positioned at the current end of file, - /// even when there are other processes or threads appending to the same file. This is - /// unlike [seek]\([SeekFrom]::[End]\(0)) followed by `write()`, which - /// has a race between seeking and writing during which another writer can write, with - /// our `write()` overwriting their data. - /// - /// Keep in mind that this does not necessarily guarantee that data appended by - /// different processes or threads does not interleave. The amount of data accepted a - /// single `write()` call depends on the operating system and file system. A - /// successful `write()` is allowed to write only part of the given data, so even if - /// you're careful to provide the whole message in a single call to `write()`, there - /// is no guarantee that it will be written out in full. If you rely on the filesystem - /// accepting the message in a single write, make sure that all data that belongs - /// together is written in one operation. This can be done by concatenating strings - /// before passing them to [`write()`]. - /// - /// If a file is opened with both read and append access, beware that after - /// opening, and after every write, the position for reading may be set at the - /// end of the file. So, before writing, save the current position (using - /// [Seek]::[stream_position]), and restore it before the next read. - /// - /// ## Note - /// - /// This function doesn't create the file if it doesn't exist. Use the - /// [`OpenOptions::create`] method to do so. - /// - /// [`write()`]: Write::write "io::Write::write" - /// [`flush()`]: Write::flush "io::Write::flush" - /// [stream_position]: Seek::stream_position "io::Seek::stream_position" - /// [seek]: Seek::seek "io::Seek::seek" - /// [Current]: SeekFrom::Current "io::SeekFrom::Current" - /// [End]: SeekFrom::End "io::SeekFrom::End" - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().append(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn append(&mut self, append: bool) -> &mut Self { - self.0.append(append); - self - } - - /// Sets the option for truncating a previous file. - /// - /// If a file is successfully opened with this option set to true, it will truncate - /// the file to 0 length if it already exists. - /// - /// The file must be opened with write access for truncate to work. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn truncate(&mut self, truncate: bool) -> &mut Self { - self.0.truncate(truncate); - self - } - - /// Sets the option to create a new file, or open it if it already exists. - /// - /// In order for the file to be created, [`OpenOptions::write`] or - /// [`OpenOptions::append`] access must be used. - /// - /// See also [`std::fs::write()`][self::write] for a simple function to - /// create a file with some given data. - /// - /// # Errors - /// - /// If `.create(true)` is set without `.write(true)` or `.append(true)`, - /// calling [`open`](Self::open) will fail with [`InvalidInput`](io::ErrorKind::InvalidInput) error. - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true).create(true).open("foo.txt"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn create(&mut self, create: bool) -> &mut Self { - self.0.create(create); - self - } - - /// Sets the option to create a new file, failing if it already exists. - /// - /// No file is allowed to exist at the target location, also no (dangling) symlink. In this - /// way, if the call succeeds, the file returned is guaranteed to be new. - /// If a file exists at the target location, creating a new file will fail with [`AlreadyExists`] - /// or another error based on the situation. See [`OpenOptions::open`] for a - /// non-exhaustive list of likely errors. - /// - /// This option is useful because it is atomic. Otherwise between checking - /// whether a file exists and creating a new one, the file may have been - /// created by another process (a [TOCTOU] race condition / attack). - /// - /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are - /// ignored. - /// - /// The file must be opened with write or append access in order to create - /// a new file. - /// - /// [`.create()`]: OpenOptions::create - /// [`.truncate()`]: OpenOptions::truncate - /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists - /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().write(true) - /// .create_new(true) - /// .open("foo.txt"); - /// ``` - #[stable(feature = "expand_open_options2", since = "1.9.0")] - pub fn create_new(&mut self, create_new: bool) -> &mut Self { - self.0.create_new(create_new); - self - } - - /// Opens a file at `path` with the options specified by `self`. - /// - /// # Errors - /// - /// This function will return an error under a number of different - /// circumstances. Some of these error conditions are listed here, together - /// with their [`io::ErrorKind`]. The mapping to [`io::ErrorKind`]s is not - /// part of the compatibility contract of the function. - /// - /// * [`NotFound`]: The specified file does not exist and neither `create` - /// or `create_new` is set. - /// * [`NotFound`]: One of the directory components of the file path does - /// not exist. - /// * [`PermissionDenied`]: The user lacks permission to get the specified - /// access rights for the file. - /// * [`PermissionDenied`]: The user lacks permission to open one of the - /// directory components of the specified path. - /// * [`AlreadyExists`]: `create_new` was specified and the file already - /// exists. - /// * [`InvalidInput`]: Invalid combinations of open options (truncate - /// without write access, create without write or append access, - /// no access mode set, etc.). - /// - /// The following errors don't match any existing [`io::ErrorKind`] at the moment: - /// * One of the directory components of the specified file path - /// was not, in fact, a directory. - /// * Filesystem-level errors: full disk, write permission - /// requested on a read-only file system, exceeded disk quota, too many - /// open files, too long filename, too many symbolic links in the - /// specified path (Unix-like systems only), etc. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// - /// let file = OpenOptions::new().read(true).open("foo.txt"); - /// ``` - /// - /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists - /// [`InvalidInput`]: io::ErrorKind::InvalidInput - /// [`NotFound`]: io::ErrorKind::NotFound - /// [`PermissionDenied`]: io::ErrorKind::PermissionDenied - #[stable(feature = "rust1", since = "1.0.0")] - pub fn open>(&self, path: P) -> io::Result { - self._open(path.as_ref()) - } - - fn _open(&self, path: &Path) -> io::Result { - fs_imp::File::open(path, &self.0).map(|inner| File { inner }) - } -} - -impl AsInner for OpenOptions { - #[inline] - fn as_inner(&self) -> &fs_imp::OpenOptions { - &self.0 - } -} - -impl AsInnerMut for OpenOptions { - #[inline] - fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { - &mut self.0 - } -} - -impl Metadata { - /// Returns the file type for this metadata. - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// - /// println!("{:?}", metadata.file_type()); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "file_type", since = "1.1.0")] - pub fn file_type(&self) -> FileType { - FileType(self.0.file_type()) - } - - /// Returns `true` if this metadata is for a directory. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_file`], and will be false for symlink metadata - /// obtained from [`symlink_metadata`]. - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert!(!metadata.is_dir()); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_dir(&self) -> bool { - self.file_type().is_dir() - } - - /// Returns `true` if this metadata is for a regular file. The - /// result is mutually exclusive to the result of - /// [`Metadata::is_dir`], and will be false for symlink metadata - /// obtained from [`symlink_metadata`]. - /// - /// 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 [`File::open`] or - /// [`OpenOptions::open`] for more information. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert!(metadata.is_file()); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_file(&self) -> bool { - self.file_type().is_file() - } - - /// Returns `true` if this metadata is for a symbolic link. - /// - /// # Examples - /// - #[cfg_attr(unix, doc = "```no_run")] - #[cfg_attr(not(unix), doc = "```ignore")] - /// use std::fs; - /// use std::path::Path; - /// use std::os::unix::fs::symlink; - /// - /// fn main() -> std::io::Result<()> { - /// let link_path = Path::new("link"); - /// symlink("/origin_does_not_exist/", link_path)?; - /// - /// let metadata = fs::symlink_metadata(link_path)?; - /// - /// assert!(metadata.is_symlink()); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "is_symlink", since = "1.58.0")] - pub fn is_symlink(&self) -> bool { - self.file_type().is_symlink() - } - - /// Returns the size of the file, in bytes, this metadata is for. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert_eq!(0, metadata.len()); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> u64 { - self.0.size() - } - - /// Returns the permissions of the file this metadata is for. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// assert!(!metadata.permissions().readonly()); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn permissions(&self) -> Permissions { - Permissions(self.0.perm()) - } - - /// Returns the last modification time listed in this metadata. - /// - /// The returned value corresponds to the `mtime` field of `stat` on Unix - /// platforms and the `ftLastWriteTime` field on Windows platforms. - /// - /// # Errors - /// - /// This field might not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// if let Ok(time) = metadata.modified() { - /// println!("{time:?}"); - /// } else { - /// println!("Not supported on this platform"); - /// } - /// Ok(()) - /// } - /// ``` - #[doc(alias = "mtime", alias = "ftLastWriteTime")] - #[stable(feature = "fs_time", since = "1.10.0")] - pub fn modified(&self) -> io::Result { - self.0.modified().map(FromInner::from_inner) - } - - /// Returns the last access time of this metadata. - /// - /// The returned value corresponds to the `atime` field of `stat` on Unix - /// platforms and the `ftLastAccessTime` field on Windows platforms. - /// - /// Note that not all platforms will keep this field update in a file's - /// metadata, for example Windows has an option to disable updating this - /// time when files are accessed and Linux similarly has `noatime`. - /// - /// # Errors - /// - /// This field might not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// if let Ok(time) = metadata.accessed() { - /// println!("{time:?}"); - /// } else { - /// println!("Not supported on this platform"); - /// } - /// Ok(()) - /// } - /// ``` - #[doc(alias = "atime", alias = "ftLastAccessTime")] - #[stable(feature = "fs_time", since = "1.10.0")] - pub fn accessed(&self) -> io::Result { - self.0.accessed().map(FromInner::from_inner) - } - - /// Returns the creation time listed in this metadata. - /// - /// The returned value corresponds to the `btime` field of `statx` on - /// Linux kernel starting from to 4.11, the `birthtime` field of `stat` on other - /// Unix platforms, and the `ftCreationTime` field on Windows platforms. - /// - /// # Errors - /// - /// This field might not be available on all platforms, and will return an - /// `Err` on platforms or filesystems where it is not available. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// - /// if let Ok(time) = metadata.created() { - /// println!("{time:?}"); - /// } else { - /// println!("Not supported on this platform or filesystem"); - /// } - /// Ok(()) - /// } - /// ``` - #[doc(alias = "btime", alias = "birthtime", alias = "ftCreationTime")] - #[stable(feature = "fs_time", since = "1.10.0")] - pub fn created(&self) -> io::Result { - self.0.created().map(FromInner::from_inner) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Metadata { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut debug = f.debug_struct("Metadata"); - debug.field("file_type", &self.file_type()); - debug.field("permissions", &self.permissions()); - debug.field("len", &self.len()); - if let Ok(modified) = self.modified() { - debug.field("modified", &modified); - } - if let Ok(accessed) = self.accessed() { - debug.field("accessed", &accessed); - } - if let Ok(created) = self.created() { - debug.field("created", &created); - } - debug.finish_non_exhaustive() - } -} - -impl AsInner for Metadata { - #[inline] - fn as_inner(&self) -> &fs_imp::FileAttr { - &self.0 - } -} - -impl FromInner for Metadata { - fn from_inner(attr: fs_imp::FileAttr) -> Metadata { - Metadata(attr) - } -} - -impl FileTimes { - /// Creates a new `FileTimes` with no times set. - /// - /// Using the resulting `FileTimes` in [`File::set_times`] will not modify any timestamps. - #[stable(feature = "file_set_times", since = "1.75.0")] - pub fn new() -> Self { - Self::default() - } - - /// Set the last access time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - pub fn set_accessed(mut self, t: SystemTime) -> Self { - self.0.set_accessed(t.into_inner()); - self - } - - /// Set the last modified time of a file. - #[stable(feature = "file_set_times", since = "1.75.0")] - pub fn set_modified(mut self, t: SystemTime) -> Self { - self.0.set_modified(t.into_inner()); - self - } -} - -impl AsInnerMut for FileTimes { - fn as_inner_mut(&mut self) -> &mut fs_imp::FileTimes { - &mut self.0 - } -} - -// For implementing OS extension traits in `std::os` -#[stable(feature = "file_set_times", since = "1.75.0")] -impl Sealed for FileTimes {} - -impl Permissions { - /// Returns `true` if these permissions describe a readonly (unwritable) file. - /// - /// # Note - /// - /// This function does not take Access Control Lists (ACLs), Unix group - /// membership and other nuances into account. - /// Therefore the return value of this function cannot be relied upon - /// to predict whether attempts to read or write the file will actually succeed. - /// - /// # Windows - /// - /// On Windows this returns [`FILE_ATTRIBUTE_READONLY`](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants). - /// If `FILE_ATTRIBUTE_READONLY` is set then writes to the file will fail - /// but the user may still have permission to change this flag. If - /// `FILE_ATTRIBUTE_READONLY` is *not* set then writes may still fail due - /// to lack of write permission. - /// The behavior of this attribute for directories depends on the Windows - /// version. - /// - /// # Unix (including macOS) - /// - /// On Unix-based platforms this checks if *any* of the owner, group or others - /// write permission bits are set. It does not consider anything else, including: - /// - /// * Whether the current user is in the file's assigned group. - /// * Permissions granted by ACL. - /// * That `root` user can write to files that do not have any write bits set. - /// * Writable files on a filesystem that is mounted read-only. - /// - /// The [`PermissionsExt`] trait gives direct access to the permission bits but - /// also does not read ACLs. - /// - /// [`PermissionsExt`]: crate::os::unix::fs::PermissionsExt - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// - /// assert_eq!(false, metadata.permissions().readonly()); - /// Ok(()) - /// } - /// ``` - #[must_use = "call `set_readonly` to modify the readonly flag"] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn readonly(&self) -> bool { - self.0.readonly() - } - - /// Modifies the readonly flag for this set of permissions. If the - /// `readonly` argument is `true`, using the resulting `Permission` will - /// update file permissions to forbid writing. Conversely, if it's `false`, - /// using the resulting `Permission` will update file permissions to allow - /// writing. - /// - /// This operation does **not** modify the files attributes. This only - /// changes the in-memory value of these attributes for this `Permissions` - /// instance. To modify the files attributes use the [`set_permissions`] - /// function which commits these attribute changes to the file. - /// - /// # Note - /// - /// `set_readonly(false)` makes the file *world-writable* on Unix. - /// You can use the [`PermissionsExt`] trait on Unix to avoid this issue. - /// - /// It also does not take Access Control Lists (ACLs) or Unix group - /// membership into account. - /// - /// # Windows - /// - /// On Windows this sets or clears [`FILE_ATTRIBUTE_READONLY`](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants). - /// If `FILE_ATTRIBUTE_READONLY` is set then writes to the file will fail - /// but the user may still have permission to change this flag. If - /// `FILE_ATTRIBUTE_READONLY` is *not* set then the write may still fail if - /// the user does not have permission to write to the file. - /// - /// In Windows 7 and earlier this attribute prevents deleting empty - /// directories. It does not prevent modifying the directory contents. - /// On later versions of Windows this attribute is ignored for directories. - /// - /// # Unix (including macOS) - /// - /// On Unix-based platforms this sets or clears the write access bit for - /// the owner, group *and* others, equivalent to `chmod a+w ` - /// or `chmod a-w ` respectively. The latter will grant write access - /// to all users! You can use the [`PermissionsExt`] trait on Unix - /// to avoid this issue. - /// - /// [`PermissionsExt`]: crate::os::unix::fs::PermissionsExt - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_readonly(true); - /// - /// // filesystem doesn't change, only the in memory state of the - /// // readonly permission - /// assert_eq!(false, metadata.permissions().readonly()); - /// - /// // just this particular `permissions`. - /// assert_eq!(true, permissions.readonly()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_readonly(&mut self, readonly: bool) { - self.0.set_readonly(readonly) - } -} - -impl FileType { - /// Tests whether this file type represents a directory. The - /// result is mutually exclusive to the results of - /// [`is_file`] and [`is_symlink`]; only zero or one of these - /// tests may pass. - /// - /// [`is_file`]: FileType::is_file - /// [`is_symlink`]: FileType::is_symlink - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); - /// - /// assert_eq!(file_type.is_dir(), false); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "file_type", since = "1.1.0")] - pub fn is_dir(&self) -> bool { - self.0.is_dir() - } - - /// Tests whether this file type represents a regular file. - /// The result is mutually exclusive to the results of - /// [`is_dir`] and [`is_symlink`]; only zero or one of these - /// tests may pass. - /// - /// 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 [`File::open`] or - /// [`OpenOptions::open`] for more information. - /// - /// [`is_dir`]: FileType::is_dir - /// [`is_symlink`]: FileType::is_symlink - /// - /// # Examples - /// - /// ```no_run - /// fn main() -> std::io::Result<()> { - /// use std::fs; - /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); - /// - /// assert_eq!(file_type.is_file(), true); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "file_type", since = "1.1.0")] - pub fn is_file(&self) -> bool { - self.0.is_file() - } - - /// Tests whether this file type represents a symbolic link. - /// The result is mutually exclusive to the results of - /// [`is_dir`] and [`is_file`]; only zero or one of these - /// tests may pass. - /// - /// The underlying [`Metadata`] struct needs to be retrieved - /// with the [`fs::symlink_metadata`] function and not the - /// [`fs::metadata`] function. The [`fs::metadata`] function - /// follows symbolic links, so [`is_symlink`] would always - /// return `false` for the target file. - /// - /// [`fs::metadata`]: metadata - /// [`fs::symlink_metadata`]: symlink_metadata - /// [`is_dir`]: FileType::is_dir - /// [`is_file`]: FileType::is_file - /// [`is_symlink`]: FileType::is_symlink - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// let metadata = fs::symlink_metadata("foo.txt")?; - /// let file_type = metadata.file_type(); - /// - /// assert_eq!(file_type.is_symlink(), false); - /// Ok(()) - /// } - /// ``` - #[must_use] - #[stable(feature = "file_type", since = "1.1.0")] - pub fn is_symlink(&self) -> bool { - self.0.is_symlink() - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for FileType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FileType") - .field("is_file", &self.is_file()) - .field("is_dir", &self.is_dir()) - .field("is_symlink", &self.is_symlink()) - .finish_non_exhaustive() - } -} - -impl AsInner for FileType { - #[inline] - fn as_inner(&self) -> &fs_imp::FileType { - &self.0 - } -} - -impl FromInner for Permissions { - fn from_inner(f: fs_imp::FilePermissions) -> Permissions { - Permissions(f) - } -} - -impl AsInner for Permissions { - #[inline] - fn as_inner(&self) -> &fs_imp::FilePermissions { - &self.0 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - self.0.next().map(|entry| entry.map(DirEntry)) - } -} - -impl DirEntry { - /// Returns the full path to the file that this entry represents. - /// - /// The full path is created by joining the original path to `read_dir` - /// with the filename of this entry. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// - /// fn main() -> std::io::Result<()> { - /// for entry in fs::read_dir(".")? { - /// let dir = entry?; - /// println!("{:?}", dir.path()); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// This prints output like: - /// - /// ```text - /// "./whatever.txt" - /// "./foo.html" - /// "./hello_world.rs" - /// ``` - /// - /// The exact text, of course, depends on what files you have in `.`. - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn path(&self) -> PathBuf { - self.0.path() - } - - /// Returns the metadata for the file that this entry points at. - /// - /// This function will not traverse symlinks if this entry points at a - /// symlink. To traverse symlinks use [`fs::metadata`] or [`fs::File::metadata`]. - /// - /// [`fs::metadata`]: metadata - /// [`fs::File::metadata`]: File::metadata - /// - /// # Platform-specific behavior - /// - /// On Windows this function is cheap to call (no extra system calls - /// needed), but on Unix platforms this function is the equivalent of - /// calling `symlink_metadata` on the path. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// if let Ok(metadata) = entry.metadata() { - /// // Now let's show our entry's permissions! - /// println!("{:?}: {:?}", entry.path(), metadata.permissions()); - /// } else { - /// println!("Couldn't get metadata for {:?}", entry.path()); - /// } - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - pub fn metadata(&self) -> io::Result { - self.0.metadata().map(Metadata) - } - - /// Returns the file type for the file that this entry points at. - /// - /// This function will not traverse symlinks if this entry points at a - /// symlink. - /// - /// # Platform-specific behavior - /// - /// On Windows and most Unix platforms this function is free (no extra - /// system calls needed), but some Unix platforms may require the equivalent - /// call to `symlink_metadata` to learn about the target file type. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// if let Ok(file_type) = entry.file_type() { - /// // Now let's show our entry's file type! - /// println!("{:?}: {:?}", entry.path(), file_type); - /// } else { - /// println!("Couldn't get file type for {:?}", entry.path()); - /// } - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - pub fn file_type(&self) -> io::Result { - self.0.file_type().map(FileType) - } - - /// Returns the file name of this directory entry without any - /// leading path component(s). - /// - /// As an example, - /// the output of the function will result in "foo" for all the following paths: - /// - "./foo" - /// - "/the/foo" - /// - "../../foo" - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}", entry.file_name()); - /// } - /// } - /// } - /// ``` - #[must_use] - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - pub fn file_name(&self) -> OsString { - self.0.file_name() - } -} - -#[stable(feature = "dir_entry_debug", since = "1.13.0")] -impl fmt::Debug for DirEntry { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DirEntry").field(&self.path()).finish() - } -} - -impl AsInner for DirEntry { - #[inline] - fn as_inner(&self) -> &fs_imp::DirEntry { - &self.0 - } -} - -/// Removes a file from the filesystem. -/// -/// Note that there is no -/// guarantee that the file is immediately deleted (e.g., depending on -/// platform, other open file descriptors may prevent immediate removal). -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `unlink` function on Unix. -/// On Windows, `DeleteFile` is used or `CreateFileW` and `SetInformationByHandle` for readonly files. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` points to a directory. -/// * The file doesn't exist. -/// * The user lacks permissions to remove the file. -/// -/// 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, -/// i.e. if a path does not exist, its removal may fail for a number of reasons, -/// such as insufficient permissions. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::remove_file("a.txt")?; -/// Ok(()) -/// } -/// ``` -#[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_file>(path: P) -> io::Result<()> { - fs_imp::remove_file(path.as_ref()) -} - -/// Given a path, 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. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `stat` function on Unix -/// and the `GetFileInformationByHandle` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to perform `metadata` call on `path`. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let attr = fs::metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// Ok(()) -/// } -/// ``` -#[doc(alias = "stat")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn metadata>(path: P) -> io::Result { - fs_imp::metadata(path.as_ref()).map(Metadata) -} - -/// Queries the metadata about a file without following symlinks. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `lstat` function on Unix -/// and the `GetFileInformationByHandle` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The user lacks permissions to perform `metadata` call on `path`. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let attr = fs::symlink_metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// Ok(()) -/// } -/// ``` -#[doc(alias = "lstat")] -#[stable(feature = "symlink_metadata", since = "1.1.0")] -pub fn symlink_metadata>(path: P) -> io::Result { - fs_imp::symlink_metadata(path.as_ref()).map(Metadata) -} - -/// Renames a file or directory to a new name, replacing the original file if -/// `to` already exists. -/// -/// This will not work if the new name is on a different mount point. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `rename` function on Unix -/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows. -/// -/// Because of this, the behavior when both `from` and `to` exist differs. On -/// Unix, if `from` is a directory, `to` must also be an (empty) directory. If -/// `from` is not a directory, `to` must also be not a directory. The behavior -/// on Windows is the same on Windows 10 1607 and higher if `FileRenameInfoEx` -/// is supported by the filesystem; otherwise, `from` can be anything, but -/// `to` must *not* be a directory. -/// -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `from` does not exist. -/// * The user lacks permissions to view contents. -/// * `from` and `to` are on separate filesystems. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt -/// Ok(()) -/// } -/// ``` -#[doc(alias = "mv", alias = "MoveFile", alias = "MoveFileEx")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { - fs_imp::rename(from.as_ref(), to.as_ref()) -} - -/// Copies the contents of one file to another. This function will also -/// copy the permission bits of the original file to the destination file. -/// -/// This function will **overwrite** the contents of `to`. -/// -/// Note that if `from` and `to` both point to the same file, then the file -/// will likely get truncated by this operation. -/// -/// On success, the total number of bytes copied is returned and it is equal to -/// the length of the `to` file as reported by `metadata`. -/// -/// If you want to copy the contents of one file to another and you’re -/// working with [`File`]s, see the [`io::copy`](io::copy()) function. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `open` function in Unix -/// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`. -/// `O_CLOEXEC` is set for returned file descriptors. -/// -/// On Linux (including Android), this function attempts to use `copy_file_range(2)`, -/// and falls back to reading and writing if that is not possible. -/// -/// On Windows, this function currently corresponds to `CopyFileEx`. Alternate -/// NTFS streams are copied but only the size of the main stream is returned by -/// this function. -/// -/// On MacOS, this function corresponds to `fclonefileat` and `fcopyfile`. -/// -/// Note that platform-specific behavior [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `from` is neither a regular file nor a symlink to a regular file. -/// * `from` does not exist. -/// * The current process does not have the permission rights to read -/// `from` or write `to`. -/// * The parent directory of `to` doesn't exist. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt -/// Ok(()) -/// } -/// ``` -#[doc(alias = "cp")] -#[doc(alias = "CopyFile", alias = "CopyFileEx")] -#[doc(alias = "fclonefileat", alias = "fcopyfile")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { - fs_imp::copy(from.as_ref(), to.as_ref()) -} - -/// Creates a new hard link on the filesystem. -/// -/// The `link` path will be a link pointing to the `original` path. Note that -/// systems often require these two paths to both be located on the same -/// filesystem. -/// -/// If `original` names a symbolic link, it is platform-specific whether the -/// symbolic link is followed. On platforms where it's possible to not follow -/// it, it is not followed, and the created hard link points to the symbolic -/// link itself. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds the `CreateHardLink` function on Windows. -/// On most Unix systems, it corresponds to the `linkat` function with no flags. -/// On Android, VxWorks, and Redox, it instead corresponds to the `link` function. -/// On MacOS, it uses the `linkat` function if it is available, but on very old -/// systems where `linkat` is not available, `link` is selected at runtime instead. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `original` path is not a file or doesn't exist. -/// * The 'link' path already exists. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt -/// Ok(()) -/// } -/// ``` -#[doc(alias = "CreateHardLink", alias = "linkat")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn hard_link, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - fs_imp::hard_link(original.as_ref(), link.as_ref()) -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `link` path will be a symbolic link pointing to the `original` path. -/// On Windows, this will be a file symlink, not a directory symlink; -/// for this reason, the platform-specific [`std::os::unix::fs::symlink`] -/// and [`std::os::windows::fs::symlink_file`] or [`symlink_dir`] should be -/// used instead to make the intent explicit. -/// -/// [`std::os::unix::fs::symlink`]: crate::os::unix::fs::symlink -/// [`std::os::windows::fs::symlink_file`]: crate::os::windows::fs::symlink_file -/// [`symlink_dir`]: crate::os::windows::fs::symlink_dir -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::soft_link("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated( - since = "1.1.0", - note = "replaced with std::os::unix::fs::symlink and \ - std::os::windows::fs::{symlink_file, symlink_dir}" -)] -pub fn soft_link, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - fs_imp::symlink(original.as_ref(), link.as_ref()) -} - -/// Reads a symbolic link, returning the file that the link points to. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `readlink` function on Unix -/// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and -/// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` is not a symbolic link. -/// * `path` does not exist. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let path = fs::read_link("a.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_link>(path: P) -> io::Result { - fs_imp::read_link(path.as_ref()) -} - -/// Returns the canonical, absolute form of a path with all intermediate -/// components normalized and symbolic links resolved. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `realpath` function on Unix -/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. -/// Note that this [may change in the future][changes]. -/// -/// On Windows, this converts the path to use [extended length path][path] -/// syntax, which allows your program to use longer path names, but means you -/// can only join backslash-delimited paths to it, and it may be incompatible -/// with other applications (if passed to the application on the command-line, -/// or written to a file another application may read). -/// -/// [changes]: io#platform-specific-behavior -/// [path]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file -/// -/// # Errors -/// -/// This function 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::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let path = fs::canonicalize("../a/../foo.txt")?; -/// Ok(()) -/// } -/// ``` -#[doc(alias = "realpath")] -#[doc(alias = "GetFinalPathNameByHandle")] -#[stable(feature = "fs_canonicalize", since = "1.5.0")] -pub fn canonicalize>(path: P) -> io::Result { - fs_imp::canonicalize(path.as_ref()) -} - -/// Creates a new, empty directory at the provided path. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `mkdir` function on Unix -/// and the `CreateDirectoryW` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// **NOTE**: If a parent of the given path doesn't exist, this function will -/// return an error. To create a directory and all its missing parents at the -/// same time, use the [`create_dir_all`] function. -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * User lacks permissions to create directory at `path`. -/// * A parent of the given path doesn't exist. (To create a directory and all -/// its missing parents at the same time, use the [`create_dir_all`] -/// function.) -/// * `path` already exists. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::create_dir("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[doc(alias = "mkdir", alias = "CreateDirectory")] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "fs_create_dir")] -pub fn create_dir>(path: P) -> io::Result<()> { - DirBuilder::new().create(path.as_ref()) -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -/// -/// This function is not atomic. If it returns an error, any parent components it was able to create -/// will remain. -/// -/// If the empty path is passed to this function, it always succeeds without -/// creating any directories. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to multiple calls to the `mkdir` -/// function on Unix and the `CreateDirectoryW` function on Windows. -/// -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// The function will return an error if any directory specified in path does not exist and -/// could not be created. There may be other error conditions; see [`fs::create_dir`] for specifics. -/// -/// Notable exception is made for situations where any of the directories -/// specified in the `path` could not be created as it was being created concurrently. -/// Such cases are considered to be successful. That is, calling `create_dir_all` -/// concurrently from multiple threads or processes is guaranteed not to fail -/// due to a race condition with itself. -/// -/// [`fs::create_dir`]: create_dir -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::create_dir_all("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn create_dir_all>(path: P) -> io::Result<()> { - DirBuilder::new().recursive(true).create(path.as_ref()) -} - -/// Removes an empty directory. -/// -/// If you want to remove a directory that is not empty, as well as all -/// of its contents recursively, consider using [`remove_dir_all`] -/// instead. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `rmdir` function on Unix -/// and the `RemoveDirectory` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` doesn't exist. -/// * `path` isn't a directory. -/// * The user lacks permissions to remove the directory at the provided `path`. -/// * The directory isn't empty. -/// -/// 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, -/// i.e. if a path does not exist, its removal may fail for a number of reasons, -/// such as insufficient permissions. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::remove_dir("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[doc(alias = "rmdir", alias = "RemoveDirectory")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir>(path: P) -> io::Result<()> { - fs_imp::remove_dir(path.as_ref()) -} - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// This function does **not** follow symbolic links and it will simply remove the -/// symbolic link itself. -/// -/// # Platform-specific behavior -/// -/// These implementation details [may change in the future][changes]. -/// -/// - "Unix-like": By default, this function currently corresponds to -/// `openat`, `fdopendir`, `unlinkat` and `lstat` -/// on Unix-family platforms, except where noted otherwise. -/// - "Windows": This function currently corresponds to `CreateFileW`, -/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`. -/// -/// ## Time-of-check to time-of-use (TOCTOU) race conditions -/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou). -/// -/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default. -/// However, on the following platforms, this protection is not provided and the function should -/// not be used in security-sensitive contexts: -/// - **Miri**: Even when emulating targets where the underlying implementation will protect against -/// TOCTOU races, Miri will not do so. -/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement -/// the required platform support to do so. -/// -/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou -/// [changes]: io#platform-specific-behavior -/// -/// # Errors -/// -/// See [`fs::remove_file`] and [`fs::remove_dir`]. -/// -/// [`remove_dir_all`] will fail if [`remove_dir`] or [`remove_file`] fail on *any* constituent -/// paths, *including* the root `path`. Consequently, -/// -/// - The directory you are deleting *must* exist, meaning that this function is *not idempotent*. -/// - [`remove_dir_all`] will fail if the `path` is *not* a directory. -/// -/// Consider ignoring the error if validating the removal is not required for your use case. -/// -/// This function may return [`io::ErrorKind::DirectoryNotEmpty`] if the directory is concurrently -/// written into, which typically indicates some contents were removed but not all. -/// [`io::ErrorKind::NotFound`] is only returned if no removal occurs. -/// -/// [`fs::remove_file`]: remove_file -/// [`fs::remove_dir`]: remove_dir -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::remove_dir_all("/some/dir")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn remove_dir_all>(path: P) -> io::Result<()> { - fs_imp::remove_dir_all(path.as_ref()) -} - -/// Returns an iterator over the entries within a directory. -/// -/// The iterator will yield instances of [io::Result]<[DirEntry]>. -/// New errors may be encountered after an iterator is initially constructed. -/// Entries for the current and parent directories (typically `.` and `..`) are -/// skipped. -/// -/// The order in which `read_dir` returns entries can change between calls. If reproducible -/// ordering is required, the entries should be explicitly sorted. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `opendir` function on Unix -/// and the `FindFirstFileEx` function on Windows. Advancing the iterator -/// currently corresponds to `readdir` on Unix and `FindNextFile` on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// The order in which this iterator returns entries is platform and filesystem -/// dependent. -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The provided `path` doesn't exist. -/// * The process lacks permissions to view the contents. -/// * The `path` points at a non-directory file. -/// -/// # Examples -/// -/// ``` -/// use std::io; -/// use std::fs::{self, DirEntry}; -/// use std::path::Path; -/// -/// // one possible implementation of walking a directory only visiting files -/// fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> io::Result<()> { -/// if dir.is_dir() { -/// for entry in fs::read_dir(dir)? { -/// let entry = entry?; -/// let path = entry.path(); -/// if path.is_dir() { -/// visit_dirs(&path, cb)?; -/// } else { -/// cb(&entry); -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -/// -/// ```rust,no_run -/// use std::{fs, io}; -/// -/// fn main() -> io::Result<()> { -/// let mut entries = fs::read_dir(".")? -/// .map(|res| res.map(|e| e.path())) -/// .collect::, io::Error>>()?; -/// -/// // The order in which `read_dir` returns entries is not guaranteed. If reproducible -/// // ordering is required the entries should be explicitly sorted. -/// -/// entries.sort(); -/// -/// // The entries have now been sorted by their path. -/// -/// Ok(()) -/// } -/// ``` -#[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_dir>(path: P) -> io::Result { - fs_imp::read_dir(path.as_ref()).map(ReadDir) -} - -/// Changes the permissions found on a file or a directory. -/// -/// # Platform-specific behavior -/// -/// This function currently corresponds to the `chmod` function on Unix -/// and the `SetFileAttributes` function on Windows. -/// Note that, this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// -/// ## Symlinks -/// On UNIX-like systems, this function will update the permission bits -/// of the file pointed to by the symlink. -/// -/// Note that this behavior can lead to privilege escalation vulnerabilities, -/// where the ability to create a symlink in one directory allows you to -/// cause the permissions of another file or directory to be modified. -/// -/// For this reason, using this function with symlinks should be avoided. -/// When possible, permissions should be set at creation time instead. -/// -/// # Rationale -/// POSIX does not specify an `lchmod` function, -/// and symlinks can be followed regardless of what permission bits are set. -/// -/// # Errors -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * `path` does not exist. -/// * The user lacks the permission to change attributes of the file. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// fn main() -> std::io::Result<()> { -/// let mut perms = fs::metadata("foo.txt")?.permissions(); -/// perms.set_readonly(true); -/// fs::set_permissions("foo.txt", perms)?; -/// Ok(()) -/// } -/// ``` -#[doc(alias = "chmod", alias = "SetFileAttributes")] -#[stable(feature = "set_permissions", since = "1.1.0")] -pub fn set_permissions>(path: P, perm: Permissions) -> io::Result<()> { - fs_imp::set_permissions(path.as_ref(), perm.0) -} - -/// Set the permissions of a file, unless it is a symlink. -/// -/// Note that the non-final path elements are allowed to be symlinks. -/// -/// # Platform-specific behavior -/// -/// Currently unimplemented on Windows. -/// -/// On Unix platforms, this results in a [`FilesystemLoop`] error if the last element is a symlink. -/// -/// This behavior may change in the future. -/// -/// [`FilesystemLoop`]: crate::io::ErrorKind::FilesystemLoop -#[doc(alias = "chmod", alias = "SetFileAttributes")] -#[unstable(feature = "set_permissions_nofollow", issue = "141607")] -pub fn set_permissions_nofollow>(path: P, perm: Permissions) -> io::Result<()> { - fs_imp::set_permissions_nofollow(path.as_ref(), perm) -} - -impl DirBuilder { - /// Creates a new set of options with default mode/security settings for all - /// platforms and also non-recursive. - /// - /// # Examples - /// - /// ``` - /// use std::fs::DirBuilder; - /// - /// let builder = DirBuilder::new(); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - #[must_use] - pub fn new() -> DirBuilder { - DirBuilder { inner: fs_imp::DirBuilder::new(), recursive: false } - } - - /// Indicates that directories should be created recursively, creating all - /// parent directories. Parents that do not exist are created with the same - /// security and permissions settings. - /// - /// This option defaults to `false`. - /// - /// # Examples - /// - /// ``` - /// use std::fs::DirBuilder; - /// - /// let mut builder = DirBuilder::new(); - /// builder.recursive(true); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - pub fn recursive(&mut self, recursive: bool) -> &mut Self { - self.recursive = recursive; - self - } - - /// Creates the specified directory with the options configured in this - /// builder. - /// - /// It is considered an error if the directory already exists unless - /// recursive mode is enabled. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::{self, DirBuilder}; - /// - /// let path = "/tmp/foo/bar/baz"; - /// DirBuilder::new() - /// .recursive(true) - /// .create(path).unwrap(); - /// - /// assert!(fs::metadata(path).unwrap().is_dir()); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - pub fn create>(&self, path: P) -> io::Result<()> { - self._create(path.as_ref()) - } - - fn _create(&self, path: &Path) -> io::Result<()> { - if self.recursive { self.create_dir_all(path) } else { self.inner.mkdir(path) } - } - - fn create_dir_all(&self, path: &Path) -> io::Result<()> { - // if path's parent is None, it is "/" path, which should - // return Ok immediately - if path == Path::new("") || path.parent() == None { - return Ok(()); - } - - let ancestors = path.ancestors(); - let mut uncreated_dirs = 0; - - for ancestor in ancestors { - // for relative paths like "foo/bar", the parent of - // "foo" will be "" which there's no need to invoke - // a mkdir syscall on - if ancestor == Path::new("") || ancestor.parent() == None { - break; - } - - match self.inner.mkdir(ancestor) { - Ok(()) => break, - Err(e) if e.kind() == io::ErrorKind::NotFound => uncreated_dirs += 1, - // we check if the err is AlreadyExists for two reasons - // - in case the path exists as a *file* - // - and to avoid calls to .is_dir() in case of other errs - // (i.e. PermissionDenied) - Err(e) if e.kind() == io::ErrorKind::AlreadyExists && ancestor.is_dir() => break, - Err(e) => return Err(e), - } - } - - // collect only the uncreated directories w/o letting the vec resize - let mut uncreated_dirs_vec = Vec::with_capacity(uncreated_dirs); - uncreated_dirs_vec.extend(ancestors.take(uncreated_dirs)); - - for uncreated_dir in uncreated_dirs_vec.iter().rev() { - if let Err(e) = self.inner.mkdir(uncreated_dir) { - if e.kind() != io::ErrorKind::AlreadyExists || !uncreated_dir.is_dir() { - return Err(e); - } - } - } - - Ok(()) - } -} - -impl AsInnerMut for DirBuilder { - #[inline] - fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder { - &mut self.inner - } -} - -/// 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)`. -/// -/// As opposed to the [`Path::exists`] method, this will only return `Ok(true)` or `Ok(false)` -/// if the path was _verified_ to exist or not exist. If its existence can neither be confirmed -/// nor denied, an `Err(_)` will be propagated 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. -/// -/// # Examples -/// -/// ```no_run -/// use std::fs; -/// -/// assert!(!fs::exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt")); -/// assert!(fs::exists("/root/secret_file.txt").is_err()); -/// ``` -/// -/// [`Path::exists`]: crate::path::Path::exists -/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou -#[stable(feature = "fs_try_exists", since = "1.81.0")] -#[inline] -pub fn exists>(path: P) -> io::Result { - fs_imp::exists(path.as_ref()) -} diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs new file mode 120000 index 0000000..2702e27 --- /dev/null +++ b/library/std/src/fs.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/fs.rs \ No newline at end of file diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs deleted file mode 100644 index dc0d11b..0000000 --- a/library/std/src/keyword_docs.rs +++ /dev/null @@ -1,2754 +0,0 @@ -#[doc(keyword = "as")] -// -/// Cast between types, rename an import, or qualify paths to associated items. -/// -/// # Type casting -/// -/// `as` is most commonly used to turn primitive types into other primitive types, but it has other -/// uses that include turning pointers into addresses, addresses into pointers, and pointers into -/// other pointers. -/// -/// ```rust -/// let thing1: u8 = 89.0 as u8; -/// assert_eq!('B' as u32, 66); -/// assert_eq!(thing1 as char, 'Y'); -/// let thing2: f32 = thing1 as f32 + 10.5; -/// assert_eq!(true as u8 + thing2 as u8, 100); -/// ``` -/// -/// In general, any cast that can be performed via ascribing the type can also be done using `as`, -/// so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (note: `let x: u32 -/// = 123` would be best in that situation). The same is not true in the other direction, however; -/// explicitly using `as` allows a few more coercions that aren't allowed implicitly, such as -/// changing the type of a raw pointer or turning closures into raw pointers. -/// -/// `as` can be seen as the primitive for `From` and `Into`: `as` only works with primitives -/// (`u8`, `bool`, `str`, pointers, ...) whereas `From` and `Into` also works with types like -/// `String` or `Vec`. -/// -/// `as` can also be used with the `_` placeholder when the destination type can be inferred. Note -/// that this can cause inference breakage and usually such code should use an explicit type for -/// both clarity and stability. This is most useful when converting pointers using `as *const _` or -/// `as *mut _` though the [`cast`][const-cast] method is recommended over `as *const _` and it is -/// [the same][mut-cast] for `as *mut _`: those methods make the intent clearer. -/// -/// # Renaming imports -/// -/// `as` is also used to rename imports in [`use`] and [`extern crate`][`crate`] statements: -/// -/// ``` -/// # #[allow(unused_imports)] -/// use std::{mem as memory, net as network}; -/// // Now you can use the names `memory` and `network` to refer to `std::mem` and `std::net`. -/// ``` -/// -/// # Qualifying paths -/// -/// You'll also find with `From` and `Into`, and indeed all traits, that `as` is used for the -/// _fully qualified path_, a means of disambiguating associated items, i.e. functions, -/// constants, and types. For example, if you have a type which implements two traits with identical -/// method names (e.g. `Into::::into` and `Into::::into`), you can clarify which method -/// you'll use with `>::into(my_thing)`[^as-use-from]. This is quite verbose, -/// but fortunately, Rust's type inference usually saves you from needing this, although it is -/// occasionally necessary, especially with methods that return a generic type like `Into::into` or -/// methods that don't take `self`. It's more common to use in macros where it can provide necessary -/// hygiene. -/// -/// [^as-use-from]: You should probably never use this syntax with `Into` and instead write -/// `T::from(my_thing)`. It just happens that there aren't any great examples for this syntax in -/// the standard library. Also, at time of writing, the compiler tends to suggest fully-qualified -/// paths to fix ambiguous `Into::into` calls, so the example should hopefully be familiar. -/// -/// # Further reading -/// -/// For more information on what `as` is capable of, see the Reference on [type cast expressions], -/// [renaming imported entities], [renaming `extern` crates] -/// and [qualified paths]. -/// -/// [type cast expressions]: ../reference/expressions/operator-expr.html#type-cast-expressions -/// [renaming imported entities]: https://doc.rust-lang.org/reference/items/use-declarations.html#as-renames -/// [renaming `extern` crates]: https://doc.rust-lang.org/reference/items/extern-crates.html#r-items.extern-crate.as -/// [qualified paths]: ../reference/paths.html#qualified-paths -/// [`crate`]: keyword.crate.html -/// [`use`]: keyword.use.html -/// [const-cast]: pointer::cast -/// [mut-cast]: primitive.pointer.html#method.cast-1 -mod as_keyword {} - -#[doc(keyword = "break")] -// -/// Exit early from a loop or labelled block. -/// -/// When `break` is encountered, execution of the associated loop body is -/// immediately terminated. -/// -/// ```rust -/// let mut last = 0; -/// -/// for x in 1..100 { -/// if x > 12 { -/// break; -/// } -/// last = x; -/// } -/// -/// assert_eq!(last, 12); -/// println!("{last}"); -/// ``` -/// -/// A break expression is normally associated with the innermost loop enclosing the -/// `break` but a label can be used to specify which enclosing loop is affected. -/// -/// ```rust -/// 'outer: for i in 1..=5 { -/// println!("outer iteration (i): {i}"); -/// -/// '_inner: for j in 1..=200 { -/// println!(" inner iteration (j): {j}"); -/// if j >= 3 { -/// // breaks from inner loop, lets outer loop continue. -/// break; -/// } -/// if i >= 2 { -/// // breaks from outer loop, and directly to "Bye". -/// break 'outer; -/// } -/// } -/// } -/// println!("Bye."); -/// ``` -/// -/// When associated with `loop`, a break expression may be used to return a value from that loop. -/// This is only valid with `loop` and not with any other type of loop. -/// If no value is specified for `break;` it returns `()`. -/// Every `break` within a loop must return the same type. -/// -/// ```rust -/// let (mut a, mut b) = (1, 1); -/// let result = loop { -/// if b > 10 { -/// break b; -/// } -/// let c = a + b; -/// a = b; -/// b = c; -/// }; -/// // first number in Fibonacci sequence over 10: -/// assert_eq!(result, 13); -/// println!("{result}"); -/// ``` -/// -/// It is also possible to exit from any *labelled* block returning the value early. -/// If no value is specified for `break;` it returns `()`. -/// -/// ```rust -/// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; -/// -/// let mut results = vec![]; -/// for input in inputs { -/// let result = 'filter: { -/// if input.len() > 3 { -/// break 'filter Err("Too long"); -/// }; -/// -/// if !input.contains("C") { -/// break 'filter Err("No Cs"); -/// }; -/// -/// Ok(input.to_uppercase()) -/// }; -/// -/// results.push(result); -/// } -/// -/// // [Ok("COW"), Ok("CAT"), Err("No Cs"), Err("Too long"), Ok("COD")] -/// println!("{:?}", results) -/// ``` -/// -/// For more details consult the [Reference on "break expression"] and the [Reference on "break and -/// loop values"]. -/// -/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions -/// [Reference on "break and loop values"]: -/// ../reference/expressions/loop-expr.html#break-and-loop-values -mod break_keyword {} - -#[doc(keyword = "const")] -// -/// Compile-time constants, compile-time blocks, compile-time evaluable functions, and raw pointers. -/// -/// ## Compile-time constants -/// -/// Sometimes a certain value is used many times throughout a program, and it can become -/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to -/// make it a variable that gets carried around to each function that needs it. In these cases, the -/// `const` keyword provides a convenient alternative to code duplication: -/// -/// ```rust -/// const THING: u32 = 0xABAD1DEA; -/// -/// let foo = 123 + THING; -/// ``` -/// -/// Constants must be explicitly typed; unlike with `let`, you can't ignore their type and let the -/// compiler figure it out. Any constant value can be defined in a `const`, which in practice happens -/// to be most things that would be reasonable to have in a constant (barring `const fn`s). For -/// example, you can't have a [`File`] as a `const`. -/// -/// [`File`]: crate::fs::File -/// -/// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses -/// all others in a Rust program. For example, if you wanted to define a constant string, it would -/// look like this: -/// -/// ```rust -/// const WORDS: &'static str = "hello rust!"; -/// ``` -/// -/// Thanks to static lifetime elision, you usually don't have to explicitly use `'static`: -/// -/// ```rust -/// const WORDS: &str = "hello convenience!"; -/// ``` -/// -/// `const` items look remarkably similar to `static` items, which introduces some confusion as -/// to which one should be used at which times. To put it simply, constants are inlined wherever -/// they're used, making using them identical to simply replacing the name of the `const` with its -/// value. Static variables, on the other hand, point to a single location in memory, which all -/// accesses share. This means that, unlike with constants, they can't have destructors, and act as -/// a single value across the entire codebase. -/// -/// Constants, like statics, should always be in `SCREAMING_SNAKE_CASE`. -/// -/// For more detail on `const`, see the [Rust Book] or the [Reference]. -/// -/// ## Compile-time blocks -/// -/// The `const` keyword can also be used to define a block of code that is evaluated at compile time. -/// This is useful for ensuring certain computations are completed before optimizations happen, as well as -/// before runtime. For more details, see the [Reference][const-blocks]. -/// -/// ## Compile-time evaluable functions -/// -/// The other main use of the `const` keyword is in `const fn`. This marks a function as being -/// callable in the body of a `const` or `static` item and in array initializers (commonly called -/// "const contexts"). `const fn` are restricted in the set of operations they can perform, to -/// ensure that they can be evaluated at compile-time. See the [Reference][const-eval] for more -/// detail. -/// -/// Turning a `fn` into a `const fn` has no effect on run-time uses of that function. -/// -/// ## Other uses of `const` -/// -/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const -/// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive]. -/// -/// [pointer primitive]: pointer -/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#constants -/// [Reference]: ../reference/items/constant-items.html -/// [const-blocks]: ../reference/expressions/block-expr.html#const-blocks -/// [const-eval]: ../reference/const_eval.html -mod const_keyword {} - -#[doc(keyword = "continue")] -// -/// Skip to the next iteration of a loop. -/// -/// When `continue` is encountered, the current iteration is terminated, returning control to the -/// loop head, typically continuing with the next iteration. -/// -/// ```rust -/// // Printing odd numbers by skipping even ones -/// for number in 1..=10 { -/// if number % 2 == 0 { -/// continue; -/// } -/// println!("{number}"); -/// } -/// ``` -/// -/// Like `break`, `continue` is normally associated with the innermost enclosing loop, but labels -/// may be used to specify the affected loop. -/// -/// ```rust -/// // Print Odd numbers under 30 with unit <= 5 -/// 'tens: for ten in 0..3 { -/// '_units: for unit in 0..=9 { -/// if unit % 2 == 0 { -/// continue; -/// } -/// if unit > 5 { -/// continue 'tens; -/// } -/// println!("{}", ten * 10 + unit); -/// } -/// } -/// ``` -/// -/// See [continue expressions] from the reference for more details. -/// -/// [continue expressions]: ../reference/expressions/loop-expr.html#continue-expressions -mod continue_keyword {} - -#[doc(keyword = "crate")] -// -/// A Rust binary or library. -/// -/// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are -/// used to specify a dependency on a crate external to the one it's declared in. Crates are the -/// fundamental compilation unit of Rust code, and can be seen as libraries or projects. More can -/// be read about crates in the [Reference]. -/// -/// ```rust ignore -/// extern crate rand; -/// extern crate my_crate as thing; -/// extern crate std; // implicitly added to the root of every Rust project -/// ``` -/// -/// The `as` keyword can be used to change what the crate is referred to as in your project. If a -/// crate name includes a dash, it is implicitly imported with the dashes replaced by underscores. -/// -/// `crate` can also be used as in conjunction with `pub` to signify that the item it's attached to -/// is public only to other members of the same crate it's in. -/// -/// ```rust -/// # #[allow(unused_imports)] -/// pub(crate) use std::io::Error as IoError; -/// pub(crate) enum CoolMarkerType { } -/// pub struct PublicThing { -/// pub(crate) semi_secret_thing: bool, -/// } -/// ``` -/// -/// `crate` is also used to represent the absolute path of a module, where `crate` refers to the -/// root of the current crate. For instance, `crate::foo::bar` refers to the name `bar` inside the -/// module `foo`, from anywhere else in the same crate. -/// -/// [Reference]: ../reference/items/extern-crates.html -mod crate_keyword {} - -#[doc(keyword = "else")] -// -/// What expression to evaluate when an [`if`] condition evaluates to [`false`]. -/// -/// `else` expressions are optional. When no else expressions are supplied it is assumed to evaluate -/// to the unit type `()`. -/// -/// The type that the `else` blocks evaluate to must be compatible with the type that the `if` block -/// evaluates to. -/// -/// As can be seen below, `else` must be followed by either: `if`, `if let`, or a block `{}` and it -/// will return the value of that expression. -/// -/// ```rust -/// let result = if true == false { -/// "oh no" -/// } else if "something" == "other thing" { -/// "oh dear" -/// } else if let Some(200) = "blarg".parse::().ok() { -/// "uh oh" -/// } else { -/// println!("Sneaky side effect."); -/// "phew, nothing's broken" -/// }; -/// ``` -/// -/// Here's another example but here we do not try and return an expression: -/// -/// ```rust -/// if true == false { -/// println!("oh no"); -/// } else if "something" == "other thing" { -/// println!("oh dear"); -/// } else if let Some(200) = "blarg".parse::().ok() { -/// println!("uh oh"); -/// } else { -/// println!("phew, nothing's broken"); -/// } -/// ``` -/// -/// The above is _still_ an expression but it will always evaluate to `()`. -/// -/// There is possibly no limit to the number of `else` blocks that could follow an `if` expression -/// however if you have several then a [`match`] expression might be preferable. -/// -/// Read more about control flow in the [Rust Book]. -/// -/// [Rust Book]: ../book/ch03-05-control-flow.html#handling-multiple-conditions-with-else-if -/// [`match`]: keyword.match.html -/// [`false`]: keyword.false.html -/// [`if`]: keyword.if.html -mod else_keyword {} - -#[doc(keyword = "enum")] -// -/// A type that can be any one of several variants. -/// -/// Enums in Rust are similar to those of other compiled languages like C, but have important -/// differences that make them considerably more powerful. What Rust calls enums are more commonly -/// known as [Algebraic Data Types][ADT] if you're coming from a functional programming background. -/// The important detail is that each enum variant can have data to go along with it. -/// -/// ```rust -/// # struct Coord; -/// enum SimpleEnum { -/// FirstVariant, -/// SecondVariant, -/// ThirdVariant, -/// } -/// -/// enum Location { -/// Unknown, -/// Anonymous, -/// Known(Coord), -/// } -/// -/// enum ComplexEnum { -/// Nothing, -/// Something(u32), -/// LotsOfThings { -/// usual_struct_stuff: bool, -/// blah: String, -/// } -/// } -/// -/// enum EmptyEnum { } -/// ``` -/// -/// The first enum shown is the usual kind of enum you'd find in a C-style language. The second -/// shows off a hypothetical example of something storing location data, with `Coord` being any -/// other type that's needed, for example a struct. The third example demonstrates the kind of -/// data a variant can store, ranging from nothing, to a tuple, to an anonymous struct. -/// -/// Instantiating enum variants involves explicitly using the enum's name as its namespace, -/// followed by one of its variants. `SimpleEnum::SecondVariant` would be an example from above. -/// When data follows along with a variant, such as with rust's built-in [`Option`] type, the data -/// is added as the type describes, for example `Option::Some(123)`. The same follows with -/// struct-like variants, with things looking like `ComplexEnum::LotsOfThings { usual_struct_stuff: -/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to [`!`] in that they cannot be -/// instantiated at all, and are used mainly to mess with the type system in interesting ways. -/// -/// For more information, take a look at the [Rust Book] or the [Reference] -/// -/// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type -/// [Rust Book]: ../book/ch06-01-defining-an-enum.html -/// [Reference]: ../reference/items/enumerations.html -mod enum_keyword {} - -#[doc(keyword = "extern")] -// -/// Link to or import external code. -/// -/// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`] -/// keyword to make your Rust code aware of other Rust crates in your project, i.e., `extern crate -/// lazy_static;`. The other use is in foreign function interfaces (FFI). -/// -/// `extern` is used in two different contexts within FFI. The first is in the form of external -/// blocks, for declaring function interfaces that Rust code can call foreign code by. This use -/// of `extern` is unsafe, since we are asserting to the compiler that all function declarations -/// are correct. If they are not, using these items may lead to undefined behavior. -/// -/// ```rust ignore -/// // SAFETY: The function declarations given below are in -/// // line with the header files of `my_c_library`. -/// #[link(name = "my_c_library")] -/// unsafe extern "C" { -/// fn my_c_function(x: i32) -> bool; -/// } -/// ``` -/// -/// This code would attempt to link with `libmy_c_library.so` on unix-like systems and -/// `my_c_library.dll` on Windows at runtime, and panic if it can't find something to link to. Rust -/// code could then use `my_c_function` as if it were any other unsafe Rust function. Working with -/// non-Rust languages and FFI is inherently unsafe, so wrappers are usually built around C APIs. -/// -/// The mirror use case of FFI is also done via the `extern` keyword: -/// -/// ```rust -/// #[unsafe(no_mangle)] -/// pub extern "C" fn callable_from_c(x: i32) -> bool { -/// x % 3 == 0 -/// } -/// ``` -/// -/// If compiled as a dylib, the resulting .so could then be linked to from a C library, and the -/// function could be used as if it was from any other library. -/// -/// For more information on FFI, check the [Rust book] or the [Reference]. -/// -/// [Rust book]: -/// ../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code -/// [Reference]: ../reference/items/external-blocks.html -/// [`crate`]: keyword.crate.html -mod extern_keyword {} - -#[doc(keyword = "false")] -// -/// A value of type [`bool`] representing logical **false**. -/// -/// `false` is the logical opposite of [`true`]. -/// -/// See the documentation for [`true`] for more information. -/// -/// [`true`]: keyword.true.html -mod false_keyword {} - -#[doc(keyword = "fn")] -// -/// A function or function pointer. -/// -/// Functions are the primary way code is executed within Rust. Function blocks, usually just -/// called functions, can be defined in a variety of different places and be assigned many -/// different attributes and modifiers. -/// -/// Standalone functions that just sit within a module not attached to anything else are common, -/// but most functions will end up being inside [`impl`] blocks, either on another type itself, or -/// as a trait impl for that type. -/// -/// ```rust -/// fn standalone_function() { -/// // code -/// } -/// -/// pub fn public_thing(argument: bool) -> String { -/// // code -/// # "".to_string() -/// } -/// -/// struct Thing { -/// foo: i32, -/// } -/// -/// impl Thing { -/// pub fn new() -> Self { -/// Self { -/// foo: 42, -/// } -/// } -/// } -/// ``` -/// -/// In addition to presenting fixed types in the form of `fn name(arg: type, ..) -> return_type`, -/// functions can also declare a list of type parameters along with trait bounds that they fall -/// into. -/// -/// ```rust -/// fn generic_function(x: T) -> (T, T, T) { -/// (x.clone(), x.clone(), x.clone()) -/// } -/// -/// fn generic_where(x: T) -> T -/// where T: std::ops::Add + Copy -/// { -/// x + x + x -/// } -/// ``` -/// -/// Declaring trait bounds in the angle brackets is functionally identical to using a `where` -/// clause. It's up to the programmer to decide which works better in each situation, but `where` -/// tends to be better when things get longer than one line. -/// -/// Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in -/// FFI. -/// -/// For more information on the various types of functions and how they're used, consult the [Rust -/// book] or the [Reference]. -/// -/// [`impl`]: keyword.impl.html -/// [`extern`]: keyword.extern.html -/// [Rust book]: ../book/ch03-03-how-functions-work.html -/// [Reference]: ../reference/items/functions.html -mod fn_keyword {} - -#[doc(keyword = "for")] -// -/// Iteration with [`in`], trait implementation with [`impl`], or [higher-ranked trait bounds] -/// (`for<'a>`). -/// -/// The `for` keyword is used in many syntactic locations: -/// -/// * `for` is used in for-in-loops (see below). -/// * `for` is used when implementing traits as in `impl Trait for Type` (see [`impl`] for more info -/// on that). -/// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq`. -/// -/// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common -/// practice within Rust, which is to loop over anything that implements [`IntoIterator`] until the -/// iterator returned by `.into_iter()` returns `None` (or the loop body uses `break`). -/// -/// ```rust -/// for i in 0..5 { -/// println!("{}", i * 2); -/// } -/// -/// for i in std::iter::repeat(5) { -/// println!("turns out {i} never stops being 5"); -/// break; // would loop forever otherwise -/// } -/// -/// 'outer: for x in 5..50 { -/// for y in 0..10 { -/// if x == y { -/// break 'outer; -/// } -/// } -/// } -/// ``` -/// -/// As shown in the example above, `for` loops (along with all other loops) can be tagged, using -/// similar syntax to lifetimes (only visually similar, entirely distinct in practice). Giving the -/// same tag to `break` breaks the tagged loop, which is useful for inner loops. It is definitely -/// not a goto. -/// -/// A `for` loop expands as shown: -/// -/// ```rust -/// # fn code() { } -/// # let iterator = 0..2; -/// for loop_variable in iterator { -/// code() -/// } -/// ``` -/// -/// ```rust -/// # fn code() { } -/// # let iterator = 0..2; -/// { -/// let result = match IntoIterator::into_iter(iterator) { -/// mut iter => loop { -/// match iter.next() { -/// None => break, -/// Some(loop_variable) => { code(); }, -/// }; -/// }, -/// }; -/// result -/// } -/// ``` -/// -/// More details on the functionality shown can be seen at the [`IntoIterator`] docs. -/// -/// For more information on for-loops, see the [Rust book] or the [Reference]. -/// -/// See also, [`loop`], [`while`]. -/// -/// [`in`]: keyword.in.html -/// [`impl`]: keyword.impl.html -/// [`loop`]: keyword.loop.html -/// [`while`]: keyword.while.html -/// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds -/// [Rust book]: -/// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for -/// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops -mod for_keyword {} - -#[doc(keyword = "if")] -// -/// Evaluate a block if a condition holds. -/// -/// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in -/// your code. However, unlike in most languages, `if` blocks can also act as expressions. -/// -/// ```rust -/// # let rude = true; -/// if 1 == 2 { -/// println!("whoops, mathematics broke"); -/// } else { -/// println!("everything's fine!"); -/// } -/// -/// let greeting = if rude { -/// "sup nerd." -/// } else { -/// "hello, friend!" -/// }; -/// -/// if let Ok(x) = "123".parse::() { -/// println!("{} double that and you get {}!", greeting, x * 2); -/// } -/// ``` -/// -/// Shown above are the three typical forms an `if` block comes in. First is the usual kind of -/// thing you'd see in many languages, with an optional `else` block. Second uses `if` as an -/// expression, which is only possible if all branches return the same type. An `if` expression can -/// be used everywhere you'd expect. The third kind of `if` block is an `if let` block, which -/// behaves similarly to using a `match` expression: -/// -/// ```rust -/// if let Some(x) = Some(123) { -/// // code -/// # let _ = x; -/// } else { -/// // something else -/// } -/// -/// match Some(123) { -/// Some(x) => { -/// // code -/// # let _ = x; -/// }, -/// _ => { -/// // something else -/// }, -/// } -/// ``` -/// -/// Each kind of `if` expression can be mixed and matched as needed. -/// -/// ```rust -/// if true == false { -/// println!("oh no"); -/// } else if "something" == "other thing" { -/// println!("oh dear"); -/// } else if let Some(200) = "blarg".parse::().ok() { -/// println!("uh oh"); -/// } else { -/// println!("phew, nothing's broken"); -/// } -/// ``` -/// -/// The `if` keyword is used in one other place in Rust, namely as a part of pattern matching -/// itself, allowing patterns such as `Some(x) if x > 200` to be used. -/// -/// For more information on `if` expressions, see the [Rust book] or the [Reference]. -/// -/// [Rust book]: ../book/ch03-05-control-flow.html#if-expressions -/// [Reference]: ../reference/expressions/if-expr.html -mod if_keyword {} - -#[doc(keyword = "impl")] -// -/// Implementations of functionality for a type, or a type implementing some functionality. -/// -/// There are two uses of the keyword `impl`: -/// * An `impl` block is an item that is used to implement some functionality for a type. -/// * An `impl Trait` in a type-position can be used to designate a type that implements a trait called `Trait`. -/// -/// # Implementing Functionality for a Type -/// -/// The `impl` keyword is primarily used to define implementations on types. Inherent -/// implementations are standalone, while trait implementations are used to implement traits for -/// types, or other traits. -/// -/// An implementation consists of definitions of functions and consts. A function defined in an -/// `impl` block can be standalone, meaning it would be called like `Vec::new()`. If the function -/// takes `self`, `&self`, or `&mut self` as its first argument, it can also be called using -/// method-call syntax, a familiar feature to any object-oriented programmer, like `vec.len()`. -/// -/// ## Inherent Implementations -/// -/// ```rust -/// struct Example { -/// number: i32, -/// } -/// -/// impl Example { -/// fn boo() { -/// println!("boo! Example::boo() was called!"); -/// } -/// -/// fn answer(&mut self) { -/// self.number += 42; -/// } -/// -/// fn get_number(&self) -> i32 { -/// self.number -/// } -/// } -/// ``` -/// -/// It matters little where an inherent implementation is defined; -/// its functionality is in scope wherever its implementing type is. -/// -/// ## Trait Implementations -/// -/// ```rust -/// struct Example { -/// number: i32, -/// } -/// -/// trait Thingy { -/// fn do_thingy(&self); -/// } -/// -/// impl Thingy for Example { -/// fn do_thingy(&self) { -/// println!("doing a thing! also, number is {}!", self.number); -/// } -/// } -/// ``` -/// -/// It matters little where a trait implementation is defined; -/// its functionality can be brought into scope by importing the trait it implements. -/// -/// For more information on implementations, see the [Rust book][book1] or the [Reference]. -/// -/// # Designating a Type that Implements Some Functionality -/// -/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be understood to mean -/// "any (or some) concrete type that implements Trait". -/// It can be used as the type of a variable declaration, -/// in [argument position](https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html) -/// or in [return position](https://rust-lang.github.io/rfcs/3425-return-position-impl-trait-in-traits.html). -/// One pertinent use case is in working with closures, which have unnameable types. -/// -/// ```rust -/// fn thing_returning_closure() -> impl Fn(i32) -> bool { -/// println!("here's a closure for you!"); -/// |x: i32| x % 3 == 0 -/// } -/// ``` -/// -/// For more information on `impl Trait` syntax, see the [Rust book][book2]. -/// -/// [book1]: ../book/ch05-03-method-syntax.html -/// [Reference]: ../reference/items/implementations.html -/// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits -mod impl_keyword {} - -#[doc(keyword = "in")] -// -/// Iterate over a series of values with [`for`]. -/// -/// The expression immediately following `in` must implement the [`IntoIterator`] trait. -/// -/// ## Literal Examples: -/// -/// * `for _ in 1..3 {}` - Iterate over an exclusive range up to but excluding 3. -/// * `for _ in 1..=3 {}` - Iterate over an inclusive range up to and including 3. -/// -/// (Read more about [range patterns]) -/// -/// [`IntoIterator`]: ../book/ch13-04-performance.html -/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns -/// [`for`]: keyword.for.html -/// -/// The other use of `in` is with the keyword `pub`. It allows users to declare an item as visible -/// only within a given scope. -/// -/// ## Literal Example: -/// -/// * `pub(in crate::outer_mod) fn outer_mod_visible_fn() {}` - fn is visible in `outer_mod` -/// -/// Starting with the 2018 edition, paths for `pub(in path)` must start with `crate`, `self` or -/// `super`. The 2015 edition may also use paths starting with `::` or modules from the crate root. -/// -/// For more information, see the [Reference]. -/// -/// [Reference]: ../reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself -mod in_keyword {} - -#[doc(keyword = "let")] -// -/// Bind a value to a variable. -/// -/// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new -/// set of variables into the current scope, as given by a pattern. -/// -/// ```rust -/// # #![allow(unused_assignments)] -/// let thing1: i32 = 100; -/// let thing2 = 200 + thing1; -/// -/// let mut changing_thing = true; -/// changing_thing = false; -/// -/// let (part1, part2) = ("first", "second"); -/// -/// struct Example { -/// a: bool, -/// b: u64, -/// } -/// -/// let Example { a, b: _ } = Example { -/// a: true, -/// b: 10004, -/// }; -/// assert!(a); -/// ``` -/// -/// The pattern is most commonly a single variable, which means no pattern matching is done and -/// the expression given is bound to the variable. Apart from that, patterns used in `let` bindings -/// can be as complicated as needed, given that the pattern is exhaustive. See the [Rust -/// book][book1] for more information on pattern matching. The type of the pattern is optionally -/// given afterwards, but if left blank is automatically inferred by the compiler if possible. -/// -/// Variables in Rust are immutable by default, and require the `mut` keyword to be made mutable. -/// -/// Multiple variables can be defined with the same name, known as shadowing. This doesn't affect -/// the original variable in any way beyond being unable to directly access it beyond the point of -/// shadowing. It continues to remain in scope, getting dropped only when it falls out of scope. -/// Shadowed variables don't need to have the same type as the variables shadowing them. -/// -/// ```rust -/// let shadowing_example = true; -/// let shadowing_example = 123.4; -/// let shadowing_example = shadowing_example as u32; -/// let mut shadowing_example = format!("cool! {shadowing_example}"); -/// shadowing_example += " something else!"; // not shadowing -/// ``` -/// -/// Other places the `let` keyword is used include along with [`if`], in the form of `if let` -/// expressions. They're useful if the pattern being matched isn't exhaustive, such as with -/// enumerations. `while let` also exists, which runs a loop with a pattern matched value until -/// that pattern can't be matched. -/// -/// For more information on the `let` keyword, see the [Rust book][book2] or the [Reference] -/// -/// [book1]: ../book/ch06-02-match.html -/// [`if`]: keyword.if.html -/// [book2]: ../book/ch18-01-all-the-places-for-patterns.html#let-statements -/// [Reference]: ../reference/statements.html#let-statements -mod let_keyword {} - -#[doc(keyword = "loop")] -// -/// Loop indefinitely. -/// -/// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside -/// it until the code uses `break` or the program exits. -/// -/// ```rust -/// loop { -/// println!("hello world forever!"); -/// # break; -/// } -/// -/// let mut i = 1; -/// loop { -/// println!("i is {i}"); -/// if i > 100 { -/// break; -/// } -/// i *= 2; -/// } -/// assert_eq!(i, 128); -/// ``` -/// -/// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as -/// expressions that return values via `break`. -/// -/// ```rust -/// let mut i = 1; -/// let something = loop { -/// i *= 2; -/// if i > 100 { -/// break i; -/// } -/// }; -/// assert_eq!(something, 128); -/// ``` -/// -/// Every `break` in a loop has to have the same type. When it's not explicitly giving something, -/// `break;` returns `()`. -/// -/// For more information on `loop` and loops in general, see the [Reference]. -/// -/// See also, [`for`], [`while`]. -/// -/// [`for`]: keyword.for.html -/// [`while`]: keyword.while.html -/// [Reference]: ../reference/expressions/loop-expr.html -mod loop_keyword {} - -#[doc(keyword = "match")] -// -/// Control flow based on pattern matching. -/// -/// `match` can be used to run code conditionally. Every pattern must -/// be handled exhaustively either explicitly or by using wildcards like -/// `_` in the `match`. Since `match` is an expression, values can also be -/// returned. -/// -/// ```rust -/// let opt = Option::None::; -/// let x = match opt { -/// Some(int) => int, -/// None => 10, -/// }; -/// assert_eq!(x, 10); -/// -/// let a_number = Option::Some(10); -/// match a_number { -/// Some(x) if x <= 5 => println!("0 to 5 num = {x}"), -/// Some(x @ 6..=10) => println!("6 to 10 num = {x}"), -/// None => panic!(), -/// // all other numbers -/// _ => panic!(), -/// } -/// ``` -/// -/// `match` can be used to gain access to the inner members of an enum -/// and use them directly. -/// -/// ```rust -/// enum Outer { -/// Double(Option, Option), -/// Single(Option), -/// Empty -/// } -/// -/// let get_inner = Outer::Double(None, Some(String::new())); -/// match get_inner { -/// Outer::Double(None, Some(st)) => println!("{st}"), -/// Outer::Single(opt) => println!("{opt:?}"), -/// _ => panic!(), -/// } -/// ``` -/// -/// For more information on `match` and matching in general, see the [Reference]. -/// -/// [Reference]: ../reference/expressions/match-expr.html -mod match_keyword {} - -#[doc(keyword = "mod")] -// -/// Organize code into [modules]. -/// -/// Use `mod` to create new [modules] to encapsulate code, including other -/// modules: -/// -/// ``` -/// mod foo { -/// mod bar { -/// type MyType = (u8, u8); -/// fn baz() {} -/// } -/// } -/// ``` -/// -/// Like [`struct`]s and [`enum`]s, a module and its content are private by -/// default, inaccessible to code outside of the module. -/// -/// To learn more about allowing access, see the documentation for the [`pub`] -/// keyword. -/// -/// [`enum`]: keyword.enum.html -/// [`pub`]: keyword.pub.html -/// [`struct`]: keyword.struct.html -/// [modules]: ../reference/items/modules.html -mod mod_keyword {} - -#[doc(keyword = "move")] -// -/// Capture a [closure]'s environment by value. -/// -/// `move` converts any variables captured by reference or mutable reference -/// to variables captured by value. -/// -/// ```rust -/// let data = vec![1, 2, 3]; -/// let closure = move || println!("captured {data:?} by value"); -/// -/// // data is no longer available, it is owned by the closure -/// ``` -/// -/// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though -/// they capture variables by `move`. This is because the traits implemented by -/// a closure type are determined by *what* the closure does with captured -/// values, not *how* it captures them: -/// -/// ```rust -/// fn create_fn() -> impl Fn() { -/// let text = "Fn".to_owned(); -/// move || println!("This is a: {text}") -/// } -/// -/// let fn_plain = create_fn(); -/// fn_plain(); -/// ``` -/// -/// `move` is often used when [threads] are involved. -/// -/// ```rust -/// let data = vec![1, 2, 3]; -/// -/// std::thread::spawn(move || { -/// println!("captured {data:?} by value") -/// }).join().unwrap(); -/// -/// // data was moved to the spawned thread, so we cannot use it here -/// ``` -/// -/// `move` is also valid before an async block. -/// -/// ```rust -/// let capture = "hello".to_owned(); -/// let block = async move { -/// println!("rust says {capture} from async block"); -/// }; -/// ``` -/// -/// For more information on the `move` keyword, see the [closures][closure] section -/// of the Rust book or the [threads] section. -/// -/// [closure]: ../book/ch13-01-closures.html -/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads -mod move_keyword {} - -#[doc(keyword = "mut")] -// -/// A mutable variable, reference, or pointer. -/// -/// `mut` can be used in several situations. The first is mutable variables, -/// which can be used anywhere you can bind a value to a variable name. Some -/// examples: -/// -/// ```rust -/// // A mutable variable in the parameter list of a function. -/// fn foo(mut x: u8, y: u8) -> u8 { -/// x += y; -/// x -/// } -/// -/// // Modifying a mutable variable. -/// # #[allow(unused_assignments)] -/// let mut a = 5; -/// a = 6; -/// -/// assert_eq!(foo(3, 4), 7); -/// assert_eq!(a, 6); -/// ``` -/// -/// The second is mutable references. They can be created from `mut` variables -/// and must be unique: no other variables can have a mutable reference, nor a -/// shared reference. -/// -/// ```rust -/// // Taking a mutable reference. -/// fn push_two(v: &mut Vec) { -/// v.push(2); -/// } -/// -/// // A mutable reference cannot be taken to a non-mutable variable. -/// let mut v = vec![0, 1]; -/// // Passing a mutable reference. -/// push_two(&mut v); -/// -/// assert_eq!(v, vec![0, 1, 2]); -/// ``` -/// -/// ```rust,compile_fail,E0502 -/// let mut v = vec![0, 1]; -/// let mut_ref_v = &mut v; -/// # #[allow(unused)] -/// let ref_v = &v; -/// mut_ref_v.push(2); -/// ``` -/// -/// Mutable raw pointers work much like mutable references, with the added -/// possibility of not pointing to a valid object. The syntax is `*mut Type`. -/// -/// More information on mutable references and pointers can be found in the [Reference]. -/// -/// [Reference]: ../reference/types/pointer.html#mutable-references-mut -mod mut_keyword {} - -#[doc(keyword = "pub")] -// -/// Make an item visible to others. -/// -/// The keyword `pub` makes any module, function, or data structure accessible from inside -/// of external modules. The `pub` keyword may also be used in a `use` declaration to re-export -/// an identifier from a namespace. -/// -/// For more information on the `pub` keyword, please see the visibility section -/// of the [reference] and for some examples, see [Rust by Example]. -/// -/// [reference]:../reference/visibility-and-privacy.html?highlight=pub#visibility-and-privacy -/// [Rust by Example]:../rust-by-example/mod/visibility.html -mod pub_keyword {} - -#[doc(keyword = "ref")] -// -/// Bind by reference during pattern matching. -/// -/// `ref` annotates pattern bindings to make them borrow rather than move. -/// It is **not** a part of the pattern as far as matching is concerned: it does -/// not affect *whether* a value is matched, only *how* it is matched. -/// -/// By default, [`match`] statements consume all they can, which can sometimes -/// be a problem, when you don't really need the value to be moved and owned: -/// -/// ```compile_fail,E0382 -/// let maybe_name = Some(String::from("Alice")); -/// // The variable 'maybe_name' is consumed here ... -/// match maybe_name { -/// Some(n) => println!("Hello, {n}"), -/// _ => println!("Hello, world"), -/// } -/// // ... and is now unavailable. -/// println!("Hello again, {}", maybe_name.unwrap_or("world".into())); -/// ``` -/// -/// Using the `ref` keyword, the value is only borrowed, not moved, making it -/// available for use after the [`match`] statement: -/// -/// ``` -/// let maybe_name = Some(String::from("Alice")); -/// // Using `ref`, the value is borrowed, not moved ... -/// match maybe_name { -/// Some(ref n) => println!("Hello, {n}"), -/// _ => println!("Hello, world"), -/// } -/// // ... so it's available here! -/// println!("Hello again, {}", maybe_name.unwrap_or("world".into())); -/// ``` -/// -/// # `&` vs `ref` -/// -/// - `&` denotes that your pattern expects a reference to an object. Hence `&` -/// is a part of said pattern: `&Foo` matches different objects than `Foo` does. -/// -/// - `ref` indicates that you want a reference to an unpacked value. It is not -/// matched against: `Foo(ref foo)` matches the same objects as `Foo(foo)`. -/// -/// See also the [Reference] for more information. -/// -/// [`match`]: keyword.match.html -/// [Reference]: ../reference/patterns.html#identifier-patterns -mod ref_keyword {} - -#[doc(keyword = "return")] -// -/// Returns a value from a function. -/// -/// A `return` marks the end of an execution path in a function: -/// -/// ``` -/// fn foo() -> i32 { -/// return 3; -/// } -/// assert_eq!(foo(), 3); -/// ``` -/// -/// `return` is not needed when the returned value is the last expression in the -/// function. In this case the `;` is omitted: -/// -/// ``` -/// fn foo() -> i32 { -/// 3 -/// } -/// assert_eq!(foo(), 3); -/// ``` -/// -/// `return` returns from the function immediately (an "early return"): -/// -/// ```no_run -/// use std::fs::File; -/// use std::io::{Error, ErrorKind, Read, Result}; -/// -/// fn main() -> Result<()> { -/// let mut file = match File::open("foo.txt") { -/// Ok(f) => f, -/// Err(e) => return Err(e), -/// }; -/// -/// let mut contents = String::new(); -/// let size = match file.read_to_string(&mut contents) { -/// Ok(s) => s, -/// Err(e) => return Err(e), -/// }; -/// -/// if contents.contains("impossible!") { -/// return Err(Error::new(ErrorKind::Other, "oh no!")); -/// } -/// -/// if size > 9000 { -/// return Err(Error::new(ErrorKind::Other, "over 9000!")); -/// } -/// -/// assert_eq!(contents, "Hello, world!"); -/// Ok(()) -/// } -/// ``` -/// -/// Within [closures] and [`async`] blocks, `return` returns a value from within the closure or -/// `async` block, not from the parent function: -/// -/// ```rust -/// fn foo() -> i32 { -/// let closure = || { -/// return 5; -/// }; -/// -/// let future = async { -/// return 10; -/// }; -/// -/// return 15; -/// } -/// -/// assert_eq!(foo(), 15); -/// ``` -/// -/// [closures]: ../book/ch13-01-closures.html -/// [`async`]: ../std/keyword.async.html -mod return_keyword {} - -#[doc(keyword = "become")] -// -/// Perform a tail-call of a function. -/// -///
-/// -/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly. -///
-/// -/// When tail calling a function, instead of its stack frame being added to the -/// stack, the stack frame of the caller is directly replaced with the callee's. -/// This means that as long as a loop in a call graph only uses tail calls, the -/// stack growth will be bounded. -/// -/// This is useful for writing functional-style code (since it prevents recursion -/// from exhausting resources) or for code optimization (since a tail call -/// *might* be cheaper than a normal call, tail calls can be used in a similar -/// manner to computed goto). -/// -/// Example of using `become` to implement functional-style `fold`: -/// ``` -/// #![feature(explicit_tail_calls)] -/// #![expect(incomplete_features)] -/// -/// fn fold(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S { -/// match slice { -/// // without `become`, on big inputs this could easily overflow the -/// // stack. using a tail call guarantees that the stack will not grow unboundedly -/// [first, rest @ ..] => become fold(rest, f(init, *first), f), -/// [] => init, -/// } -/// } -/// ``` -/// -/// Compilers can already perform "tail call optimization" -- they can replace normal -/// calls with tail calls, although there are no guarantees that this will be done. -/// However, to perform TCO, the call needs to be the last thing that happens -/// in the functions and be returned from it. This requirement is often broken -/// by drop code for locals, which is run after computing the return expression: -/// -/// ``` -/// fn example() { -/// let string = "meow".to_owned(); -/// println!("{string}"); -/// return help(); // this is *not* the last thing that happens in `example`... -/// } -/// -/// // ... because it is desugared to this: -/// fn example_desugared() { -/// let string = "meow".to_owned(); -/// println!("{string}"); -/// let tmp = help(); -/// drop(string); -/// return tmp; -/// } -/// -/// fn help() {} -/// ``` -/// -/// For this reason, `become` also changes the drop order, such that locals are -/// dropped *before* evaluating the call. -/// -/// In order to guarantee that the compiler can perform a tail call, `become` -/// currently has these requirements: -/// 1. callee and caller must have the same ABI, arguments, and return type -/// 2. callee and caller must not have varargs -/// 3. caller must not be marked with `#[track_caller]` -/// - callee is allowed to be marked with `#[track_caller]` as otherwise -/// adding `#[track_caller]` would be a breaking change. if callee is -/// marked with `#[track_caller]` a tail call is not guaranteed. -/// 4. callee and caller cannot be a closure -/// (unless it's coerced to a function pointer) -/// -/// It is possible to tail-call a function pointer: -/// ``` -/// #![feature(explicit_tail_calls)] -/// #![expect(incomplete_features)] -/// -/// #[derive(Copy, Clone)] -/// enum Inst { Inc, Dec } -/// -/// fn dispatch(stream: &[Inst], state: u32) -> u32 { -/// const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement]; -/// match stream { -/// [inst, rest @ ..] => become TABLE[*inst as usize](rest, state), -/// [] => state, -/// } -/// } -/// -/// fn increment(stream: &[Inst], state: u32) -> u32 { -/// become dispatch(stream, state + 1) -/// } -/// -/// fn decrement(stream: &[Inst], state: u32) -> u32 { -/// become dispatch(stream, state - 1) -/// } -/// -/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc]; -/// assert_eq!(dispatch(program, 0), 2); -/// ``` -mod become_keyword {} - -#[doc(keyword = "self")] -// -/// The receiver of a method, or the current module. -/// -/// `self` is used in two situations: referencing the current module and marking -/// the receiver of a method. -/// -/// In paths, `self` can be used to refer to the current module, either in a -/// [`use`] statement or in a path to access an element: -/// -/// ``` -/// # #![allow(unused_imports)] -/// use std::io::{self, Read}; -/// ``` -/// -/// Is functionally the same as: -/// -/// ``` -/// # #![allow(unused_imports)] -/// use std::io; -/// use std::io::Read; -/// ``` -/// -/// Using `self` to access an element in the current module: -/// -/// ``` -/// # #![allow(dead_code)] -/// # fn main() {} -/// fn foo() {} -/// fn bar() { -/// self::foo() -/// } -/// ``` -/// -/// `self` as the current receiver for a method allows to omit the parameter -/// type most of the time. With the exception of this particularity, `self` is -/// used much like any other parameter: -/// -/// ``` -/// struct Foo(i32); -/// -/// impl Foo { -/// // No `self`. -/// fn new() -> Self { -/// Self(0) -/// } -/// -/// // Consuming `self`. -/// fn consume(self) -> Self { -/// Self(self.0 + 1) -/// } -/// -/// // Borrowing `self`. -/// fn borrow(&self) -> &i32 { -/// &self.0 -/// } -/// -/// // Borrowing `self` mutably. -/// fn borrow_mut(&mut self) -> &mut i32 { -/// &mut self.0 -/// } -/// } -/// -/// // This method must be called with a `Type::` prefix. -/// let foo = Foo::new(); -/// assert_eq!(foo.0, 0); -/// -/// // Those two calls produces the same result. -/// let foo = Foo::consume(foo); -/// assert_eq!(foo.0, 1); -/// let foo = foo.consume(); -/// assert_eq!(foo.0, 2); -/// -/// // Borrowing is handled automatically with the second syntax. -/// let borrow_1 = Foo::borrow(&foo); -/// let borrow_2 = foo.borrow(); -/// assert_eq!(borrow_1, borrow_2); -/// -/// // Borrowing mutably is handled automatically too with the second syntax. -/// let mut foo = Foo::new(); -/// *Foo::borrow_mut(&mut foo) += 1; -/// assert_eq!(foo.0, 1); -/// *foo.borrow_mut() += 1; -/// assert_eq!(foo.0, 2); -/// ``` -/// -/// Note that this automatic conversion when calling `foo.method()` is not -/// limited to the examples above. See the [Reference] for more information. -/// -/// [`use`]: keyword.use.html -/// [Reference]: ../reference/items/associated-items.html#methods -mod self_keyword {} - -// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can replace -// these two lines with `#[doc(keyword = "Self")]` and update `is_doc_keyword` in -// `CheckAttrVisitor`. -#[doc(alias = "Self")] -#[doc(keyword = "SelfTy")] -// -/// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type -/// definition. -/// -/// Within a type definition: -/// -/// ``` -/// # #![allow(dead_code)] -/// struct Node { -/// elem: i32, -/// // `Self` is a `Node` here. -/// next: Option>, -/// } -/// ``` -/// -/// In an [`impl`] block: -/// -/// ``` -/// struct Foo(i32); -/// -/// impl Foo { -/// fn new() -> Self { -/// Self(0) -/// } -/// } -/// -/// assert_eq!(Foo::new().0, Foo(0).0); -/// ``` -/// -/// Generic parameters are implicit with `Self`: -/// -/// ``` -/// # #![allow(dead_code)] -/// struct Wrap { -/// elem: T, -/// } -/// -/// impl Wrap { -/// fn new(elem: T) -> Self { -/// Self { elem } -/// } -/// } -/// ``` -/// -/// In a [`trait`] definition and related [`impl`] block: -/// -/// ``` -/// trait Example { -/// fn example() -> Self; -/// } -/// -/// struct Foo(i32); -/// -/// impl Example for Foo { -/// fn example() -> Self { -/// Self(42) -/// } -/// } -/// -/// assert_eq!(Foo::example().0, Foo(42).0); -/// ``` -/// -/// [`impl`]: keyword.impl.html -/// [`trait`]: keyword.trait.html -mod self_upper_keyword {} - -#[doc(keyword = "static")] -// -/// A static item is a value which is valid for the entire duration of your -/// program (a `'static` lifetime). -/// -/// On the surface, `static` items seem very similar to [`const`]s: both contain -/// a value, both require type annotations and both can only be initialized with -/// constant functions and values. However, `static`s are notably different in -/// that they represent a location in memory. That means that you can have -/// references to `static` items and potentially even modify them, making them -/// essentially global variables. -/// -/// Static items do not call [`drop`] at the end of the program. -/// -/// There are two types of `static` items: those declared in association with -/// the [`mut`] keyword and those without. -/// -/// Static items cannot be moved: -/// -/// ```rust,compile_fail,E0507 -/// static VEC: Vec = vec![]; -/// -/// fn move_vec(v: Vec) -> Vec { -/// v -/// } -/// -/// // This line causes an error -/// move_vec(VEC); -/// ``` -/// -/// # Simple `static`s -/// -/// Accessing non-[`mut`] `static` items is considered safe, but some -/// restrictions apply. Most notably, the type of a `static` value needs to -/// implement the [`Sync`] trait, ruling out interior mutability containers -/// like [`RefCell`]. See the [Reference] for more information. -/// -/// ```rust -/// static FOO: [i32; 5] = [1, 2, 3, 4, 5]; -/// -/// let r1 = &FOO as *const _; -/// let r2 = &FOO as *const _; -/// // With a strictly read-only static, references will have the same address -/// assert_eq!(r1, r2); -/// // A static item can be used just like a variable in many cases -/// println!("{FOO:?}"); -/// ``` -/// -/// # Mutable `static`s -/// -/// If a `static` item is declared with the [`mut`] keyword, then it is allowed -/// to be modified by the program. However, accessing mutable `static`s can -/// cause undefined behavior in a number of ways, for example due to data races -/// in a multithreaded context. As such, all accesses to mutable `static`s -/// require an [`unsafe`] block. -/// -/// When possible, it's often better to use a non-mutable `static` with an -/// interior mutable type such as [`Mutex`], [`OnceLock`], or an [atomic]. -/// -/// Despite their unsafety, mutable `static`s are necessary in many contexts: -/// they can be used to represent global state shared by the whole program or in -/// [`extern`] blocks to bind to variables from C libraries. -/// -/// In an [`extern`] block: -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// unsafe extern "C" { -/// static mut ERROR_MESSAGE: *mut std::os::raw::c_char; -/// } -/// ``` -/// -/// Mutable `static`s, just like simple `static`s, have some restrictions that -/// apply to them. See the [Reference] for more information. -/// -/// [`const`]: keyword.const.html -/// [`extern`]: keyword.extern.html -/// [`mut`]: keyword.mut.html -/// [`unsafe`]: keyword.unsafe.html -/// [`Mutex`]: sync::Mutex -/// [`OnceLock`]: sync::OnceLock -/// [`RefCell`]: cell::RefCell -/// [atomic]: sync::atomic -/// [Reference]: ../reference/items/static-items.html -mod static_keyword {} - -#[doc(keyword = "struct")] -// -/// A type that is composed of other types. -/// -/// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit -/// structs. -/// -/// ```rust -/// struct Regular { -/// field1: f32, -/// field2: String, -/// pub field3: bool -/// } -/// -/// struct Tuple(u32, String); -/// -/// struct Unit; -/// ``` -/// -/// Regular structs are the most commonly used. Each field defined within them has a name and a -/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a -/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding -/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be -/// directly accessed and modified. -/// -/// Tuple structs are similar to regular structs, but its fields have no names. They are used like -/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax. For accessing -/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`, -/// etc, starting at zero. -/// -/// Unit structs are most commonly used as marker. They have a size of zero bytes, but unlike empty -/// enums they can be instantiated, making them isomorphic to the unit type `()`. Unit structs are -/// useful when you need to implement a trait on something, but don't need to store any data inside -/// it. -/// -/// # Instantiation -/// -/// Structs can be instantiated in different ways, all of which can be mixed and -/// matched as needed. The most common way to make a new struct is via a constructor method such as -/// `new()`, but when that isn't available (or you're writing the constructor itself), struct -/// literal syntax is used: -/// -/// ```rust -/// # struct Foo { field1: f32, field2: String, etc: bool } -/// let example = Foo { -/// field1: 42.0, -/// field2: "blah".to_string(), -/// etc: true, -/// }; -/// ``` -/// -/// It's only possible to directly instantiate a struct using struct literal syntax when all of its -/// fields are visible to you. -/// -/// There are a handful of shortcuts provided to make writing constructors more convenient, most -/// common of which is the Field Init shorthand. When there is a variable and a field of the same -/// name, the assignment can be simplified from `field: field` into simply `field`. The following -/// example of a hypothetical constructor demonstrates this: -/// -/// ```rust -/// struct User { -/// name: String, -/// admin: bool, -/// } -/// -/// impl User { -/// pub fn new(name: String) -> Self { -/// Self { -/// name, -/// admin: false, -/// } -/// } -/// } -/// ``` -/// -/// Another shortcut for struct instantiation is available, used when you need to make a new -/// struct that has the same values as most of a previous struct of the same type, called struct -/// update syntax: -/// -/// ```rust -/// # struct Foo { field1: String, field2: () } -/// # let thing = Foo { field1: "".to_string(), field2: () }; -/// let updated_thing = Foo { -/// field1: "a new value".to_string(), -/// ..thing -/// }; -/// ``` -/// -/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's -/// name as a prefix: `Foo(123, false, 0.1)`. -/// -/// Empty structs are instantiated with just their name, and don't need anything else. `let thing = -/// EmptyStruct;` -/// -/// # Style conventions -/// -/// Structs are always written in UpperCamelCase, with few exceptions. While the trailing comma on a -/// struct's list of fields can be omitted, it's usually kept for convenience in adding and -/// removing fields down the line. -/// -/// For more information on structs, take a look at the [Rust Book][book] or the -/// [Reference][reference]. -/// -/// [`PhantomData`]: marker::PhantomData -/// [book]: ../book/ch05-01-defining-structs.html -/// [reference]: ../reference/items/structs.html -mod struct_keyword {} - -#[doc(keyword = "super")] -// -/// The parent of the current [module]. -/// -/// ```rust -/// # #![allow(dead_code)] -/// # fn main() {} -/// mod a { -/// pub fn foo() {} -/// } -/// mod b { -/// pub fn foo() { -/// super::a::foo(); // call a's foo function -/// } -/// } -/// ``` -/// -/// It is also possible to use `super` multiple times: `super::super::foo`, -/// going up the ancestor chain. -/// -/// See the [Reference] for more information. -/// -/// [module]: ../reference/items/modules.html -/// [Reference]: ../reference/paths.html#super -mod super_keyword {} - -#[doc(keyword = "trait")] -// -/// A common interface for a group of types. -/// -/// A `trait` is like an interface that data types can implement. When a type -/// implements a trait it can be treated abstractly as that trait using generics -/// or trait objects. -/// -/// Traits can be made up of three varieties of associated items: -/// -/// - functions and methods -/// - types -/// - constants -/// -/// Traits may also contain additional type parameters. Those type parameters -/// or the trait itself can be constrained by other traits. -/// -/// Traits can serve as markers or carry other logical semantics that -/// aren't expressed through their items. When a type implements that -/// trait it is promising to uphold its contract. [`Send`] and [`Sync`] are two -/// such marker traits present in the standard library. -/// -/// See the [Reference][Ref-Traits] for a lot more information on traits. -/// -/// # Examples -/// -/// Traits are declared using the `trait` keyword. Types can implement them -/// using [`impl`] `Trait` [`for`] `Type`: -/// -/// ```rust -/// trait Zero { -/// const ZERO: Self; -/// fn is_zero(&self) -> bool; -/// } -/// -/// impl Zero for i32 { -/// const ZERO: Self = 0; -/// -/// fn is_zero(&self) -> bool { -/// *self == Self::ZERO -/// } -/// } -/// -/// assert_eq!(i32::ZERO, 0); -/// assert!(i32::ZERO.is_zero()); -/// assert!(!4.is_zero()); -/// ``` -/// -/// With an associated type: -/// -/// ```rust -/// trait Builder { -/// type Built; -/// -/// fn build(&self) -> Self::Built; -/// } -/// ``` -/// -/// Traits can be generic, with constraints or without: -/// -/// ```rust -/// trait MaybeFrom { -/// fn maybe_from(value: T) -> Option -/// where -/// Self: Sized; -/// } -/// ``` -/// -/// Traits can build upon the requirements of other traits. In the example -/// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**: -/// -/// ```rust -/// trait ThreeIterator: Iterator { -/// fn next_three(&mut self) -> Option<[Self::Item; 3]>; -/// } -/// ``` -/// -/// Traits can be used in functions, as parameters: -/// -/// ```rust -/// # #![allow(dead_code)] -/// fn debug_iter(it: I) where I::Item: std::fmt::Debug { -/// for elem in it { -/// println!("{elem:#?}"); -/// } -/// } -/// -/// // u8_len_1, u8_len_2 and u8_len_3 are equivalent -/// -/// fn u8_len_1(val: impl Into>) -> usize { -/// val.into().len() -/// } -/// -/// fn u8_len_2>>(val: T) -> usize { -/// val.into().len() -/// } -/// -/// fn u8_len_3(val: T) -> usize -/// where -/// T: Into>, -/// { -/// val.into().len() -/// } -/// ``` -/// -/// Or as return types: -/// -/// ```rust -/// # #![allow(dead_code)] -/// fn from_zero_to(v: u8) -> impl Iterator { -/// (0..v).into_iter() -/// } -/// ``` -/// -/// The use of the [`impl`] keyword in this position allows the function writer -/// to hide the concrete type as an implementation detail which can change -/// without breaking user's code. -/// -/// # Trait objects -/// -/// A *trait object* is an opaque value of another type that implements a set of -/// traits. A trait object implements all specified traits as well as their -/// supertraits (if any). -/// -/// The syntax is the following: `dyn BaseTrait + AutoTrait1 + ... AutoTraitN`. -/// Only one `BaseTrait` can be used so this will not compile: -/// -/// ```rust,compile_fail,E0225 -/// trait A {} -/// trait B {} -/// -/// let _: Box; -/// ``` -/// -/// Neither will this, which is a syntax error: -/// -/// ```rust,compile_fail -/// trait A {} -/// trait B {} -/// -/// let _: Box; -/// ``` -/// -/// On the other hand, this is correct: -/// -/// ```rust -/// trait A {} -/// -/// let _: Box; -/// ``` -/// -/// The [Reference][Ref-Trait-Objects] has more information about trait objects, -/// their limitations and the differences between editions. -/// -/// # Unsafe traits -/// -/// Some traits may be unsafe to implement. Using the [`unsafe`] keyword in -/// front of the trait's declaration is used to mark this: -/// -/// ```rust -/// unsafe trait UnsafeTrait {} -/// -/// unsafe impl UnsafeTrait for i32 {} -/// ``` -/// -/// # Differences between the 2015 and 2018 editions -/// -/// In the 2015 edition the parameters pattern was not needed for traits: -/// -/// ```rust,edition2015 -/// # #![allow(anonymous_parameters)] -/// trait Tr { -/// fn f(i32); -/// } -/// ``` -/// -/// This behavior is no longer valid in edition 2018. -/// -/// [`for`]: keyword.for.html -/// [`impl`]: keyword.impl.html -/// [`unsafe`]: keyword.unsafe.html -/// [Ref-Traits]: ../reference/items/traits.html -/// [Ref-Trait-Objects]: ../reference/types/trait-object.html -mod trait_keyword {} - -#[doc(keyword = "true")] -// -/// A value of type [`bool`] representing logical **true**. -/// -/// Logically `true` is not equal to [`false`]. -/// -/// ## Control structures that check for **true** -/// -/// Several of Rust's control structures will check for a `bool` condition evaluating to **true**. -/// -/// * The condition in an [`if`] expression must be of type `bool`. -/// Whenever that condition evaluates to **true**, the `if` expression takes -/// on the value of the first block. If however, the condition evaluates -/// to `false`, the expression takes on value of the `else` block if there is one. -/// -/// * [`while`] is another control flow construct expecting a `bool`-typed condition. -/// As long as the condition evaluates to **true**, the `while` loop will continually -/// evaluate its associated block. -/// -/// * [`match`] arms can have guard clauses on them. -/// -/// [`if`]: keyword.if.html -/// [`while`]: keyword.while.html -/// [`match`]: ../reference/expressions/match-expr.html#match-guards -/// [`false`]: keyword.false.html -mod true_keyword {} - -#[doc(keyword = "type")] -// -/// Define an [alias] for an existing type. -/// -/// The syntax is `type Name = ExistingType;`. -/// -/// # Examples -/// -/// `type` does **not** create a new type: -/// -/// ```rust -/// type Meters = u32; -/// type Kilograms = u32; -/// -/// let m: Meters = 3; -/// let k: Kilograms = 3; -/// -/// assert_eq!(m, k); -/// ``` -/// -/// A type can be generic: -/// -/// ```rust -/// # use std::sync::{Arc, Mutex}; -/// type ArcMutex = Arc>; -/// ``` -/// -/// In traits, `type` is used to declare an [associated type]: -/// -/// ```rust -/// trait Iterator { -/// // associated type declaration -/// type Item; -/// fn next(&mut self) -> Option; -/// } -/// -/// struct Once(Option); -/// -/// impl Iterator for Once { -/// // associated type definition -/// type Item = T; -/// fn next(&mut self) -> Option { -/// self.0.take() -/// } -/// } -/// ``` -/// -/// [`trait`]: keyword.trait.html -/// [associated type]: ../reference/items/associated-items.html#associated-types -/// [alias]: ../reference/items/type-aliases.html -mod type_keyword {} - -#[doc(keyword = "unsafe")] -// -/// Code or interfaces whose [memory safety] cannot be verified by the type -/// system. -/// -/// The `unsafe` keyword has two uses: -/// - to declare the existence of contracts the compiler can't check (`unsafe fn` and `unsafe -/// trait`), -/// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe -/// {}` and `unsafe impl`, but also `unsafe fn` -- see below). -/// -/// # Unsafe abilities -/// -/// **No matter what, Safe Rust can't cause Undefined Behavior**. This is -/// referred to as [soundness]: a well-typed program actually has the desired -/// properties. The [Nomicon][nomicon-soundness] has a more detailed explanation -/// on the subject. -/// -/// To ensure soundness, Safe Rust is restricted enough that it can be -/// automatically checked. Sometimes, however, it is necessary to write code -/// that is correct for reasons which are too clever for the compiler to -/// understand. In those cases, you need to use Unsafe Rust. -/// -/// Here are the abilities Unsafe Rust has in addition to Safe Rust: -/// -/// - Dereference [raw pointers] -/// - Implement `unsafe` [`trait`]s -/// - Call `unsafe` functions -/// - Mutate [`static`]s (including [`extern`]al ones) -/// - Access fields of [`union`]s -/// -/// However, this extra power comes with extra responsibilities: it is now up to -/// you to ensure soundness. The `unsafe` keyword helps by clearly marking the -/// pieces of code that need to worry about this. -/// -/// ## The different meanings of `unsafe` -/// -/// Not all uses of `unsafe` are equivalent: some are here to mark the existence -/// of a contract the programmer must check, others are to say "I have checked -/// the contract, go ahead and do this". The following -/// [discussion on Rust Internals] has more in-depth explanations about this but -/// here is a summary of the main points: -/// -/// - `unsafe fn`: calling this function means abiding by a contract the -/// compiler cannot enforce. -/// - `unsafe trait`: implementing the [`trait`] means abiding by a -/// contract the compiler cannot enforce. -/// - `unsafe {}`: the contract necessary to call the operations inside the -/// block has been checked by the programmer and is guaranteed to be respected. -/// - `unsafe impl`: the contract necessary to implement the trait has been -/// checked by the programmer and is guaranteed to be respected. -/// -/// See the [Rustonomicon] and the [Reference] for more information. -/// -/// # Examples -/// -/// ## Marking elements as `unsafe` -/// -/// `unsafe` can be used on functions. Note that functions and statics declared -/// in [`extern`] blocks are implicitly marked as `unsafe` (but not functions -/// declared as `extern "something" fn ...`). Mutable statics are always unsafe, -/// wherever they are declared. Methods can also be declared as `unsafe`: -/// -/// ```rust -/// # #![allow(dead_code)] -/// static mut FOO: &str = "hello"; -/// -/// unsafe fn unsafe_fn() {} -/// -/// unsafe extern "C" { -/// fn unsafe_extern_fn(); -/// static BAR: *mut u32; -/// } -/// -/// trait SafeTraitWithUnsafeMethod { -/// unsafe fn unsafe_method(&self); -/// } -/// -/// struct S; -/// -/// impl S { -/// unsafe fn unsafe_method_on_struct() {} -/// } -/// ``` -/// -/// Traits can also be declared as `unsafe`: -/// -/// ```rust -/// unsafe trait UnsafeTrait {} -/// ``` -/// -/// Since `unsafe fn` and `unsafe trait` indicate that there is a safety -/// contract that the compiler cannot enforce, documenting it is important. The -/// standard library has many examples of this, like the following which is an -/// extract from [`Vec::set_len`]. The `# Safety` section explains the contract -/// that must be fulfilled to safely call the function. -/// -/// ```rust,ignore (stub-to-show-doc-example) -/// /// Forces the length of the vector to `new_len`. -/// /// -/// /// This is a low-level operation that maintains none of the normal -/// /// invariants of the type. Normally changing the length of a vector -/// /// is done using one of the safe operations instead, such as -/// /// `truncate`, `resize`, `extend`, or `clear`. -/// /// -/// /// # Safety -/// /// -/// /// - `new_len` must be less than or equal to `capacity()`. -/// /// - The elements at `old_len..new_len` must be initialized. -/// pub unsafe fn set_len(&mut self, new_len: usize) -/// ``` -/// -/// ## Using `unsafe {}` blocks and `impl`s -/// -/// Performing `unsafe` operations requires an `unsafe {}` block: -/// -/// ```rust -/// # #![allow(dead_code)] -/// #![deny(unsafe_op_in_unsafe_fn)] -/// -/// /// Dereference the given pointer. -/// /// -/// /// # Safety -/// /// -/// /// `ptr` must be aligned and must not be dangling. -/// unsafe fn deref_unchecked(ptr: *const i32) -> i32 { -/// // SAFETY: the caller is required to ensure that `ptr` is aligned and dereferenceable. -/// unsafe { *ptr } -/// } -/// -/// let a = 3; -/// let b = &a as *const _; -/// // SAFETY: `a` has not been dropped and references are always aligned, -/// // so `b` is a valid address. -/// unsafe { assert_eq!(*b, deref_unchecked(b)); }; -/// ``` -/// -/// ## `unsafe` and traits -/// -/// The interactions of `unsafe` and traits can be surprising, so let us contrast the -/// two combinations of safe `fn` in `unsafe trait` and `unsafe fn` in safe trait using two -/// examples: -/// -/// ```rust -/// /// # Safety -/// /// -/// /// `make_even` must return an even number. -/// unsafe trait MakeEven { -/// fn make_even(&self) -> i32; -/// } -/// -/// // SAFETY: Our `make_even` always returns something even. -/// unsafe impl MakeEven for i32 { -/// fn make_even(&self) -> i32 { -/// self << 1 -/// } -/// } -/// -/// fn use_make_even(x: impl MakeEven) { -/// if x.make_even() % 2 == 1 { -/// // SAFETY: this can never happen, because all `MakeEven` implementations -/// // ensure that `make_even` returns something even. -/// unsafe { std::hint::unreachable_unchecked() }; -/// } -/// } -/// ``` -/// -/// Note how the safety contract of the trait is upheld by the implementation, and is itself used to -/// uphold the safety contract of the unsafe function `unreachable_unchecked` called by -/// `use_make_even`. `make_even` itself is a safe function because its *callers* do not have to -/// worry about any contract, only the *implementation* of `MakeEven` is required to uphold a -/// certain contract. `use_make_even` is safe because it can use the promise made by `MakeEven` -/// implementations to uphold the safety contract of the `unsafe fn unreachable_unchecked` it calls. -/// -/// It is also possible to have `unsafe fn` in a regular safe `trait`: -/// -/// ```rust -/// # #![feature(never_type)] -/// #![deny(unsafe_op_in_unsafe_fn)] -/// -/// trait Indexable { -/// const LEN: usize; -/// -/// /// # Safety -/// /// -/// /// The caller must ensure that `idx < LEN`. -/// unsafe fn idx_unchecked(&self, idx: usize) -> i32; -/// } -/// -/// // The implementation for `i32` doesn't need to do any contract reasoning. -/// impl Indexable for i32 { -/// const LEN: usize = 1; -/// -/// /// See `Indexable` for the safety contract. -/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { -/// debug_assert_eq!(idx, 0); -/// *self -/// } -/// } -/// -/// // The implementation for arrays exploits the function contract to -/// // make use of `get_unchecked` on slices and avoid a run-time check. -/// impl Indexable for [i32; 42] { -/// const LEN: usize = 42; -/// -/// /// See `Indexable` for the safety contract. -/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { -/// // SAFETY: As per this trait's documentation, the caller ensures -/// // that `idx < 42`. -/// unsafe { *self.get_unchecked(idx) } -/// } -/// } -/// -/// // The implementation for the never type declares a length of 0, -/// // which means `idx_unchecked` can never be called. -/// impl Indexable for ! { -/// const LEN: usize = 0; -/// -/// /// See `Indexable` for the safety contract. -/// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { -/// // SAFETY: As per this trait's documentation, the caller ensures -/// // that `idx < 0`, which is impossible, so this is dead code. -/// unsafe { std::hint::unreachable_unchecked() } -/// } -/// } -/// -/// fn use_indexable(x: I, idx: usize) -> i32 { -/// if idx < I::LEN { -/// // SAFETY: We have checked that `idx < I::LEN`. -/// unsafe { x.idx_unchecked(idx) } -/// } else { -/// panic!("index out-of-bounds") -/// } -/// } -/// ``` -/// -/// This time, `use_indexable` is safe because it uses a run-time check to discharge the safety -/// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing -/// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation -/// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation -/// to contend with. Of course, the implementation may choose to call other unsafe operations, and -/// then it needs an `unsafe` *block* to indicate it discharged the proof obligations of its -/// callees. For that purpose it can make use of the contract that all its callers must uphold -- -/// the fact that `idx < LEN`. -/// -/// Note that unlike normal `unsafe fn`, an `unsafe fn` in a trait implementation does not get to -/// just pick an arbitrary safety contract! It *has* to use the safety contract defined by the trait -/// (or one with weaker preconditions). -/// -/// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond -/// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare -/// that some of its functions have *postconditions* that go beyond those encoded in the return type -/// (such as returning an even integer). If a trait needs a function with both extra precondition -/// and extra postcondition, then it needs an `unsafe fn` in an `unsafe trait`. -/// -/// [`extern`]: keyword.extern.html -/// [`trait`]: keyword.trait.html -/// [`static`]: keyword.static.html -/// [`union`]: keyword.union.html -/// [`impl`]: keyword.impl.html -/// [raw pointers]: ../reference/types/pointer.html -/// [memory safety]: ../book/ch19-01-unsafe-rust.html -/// [Rustonomicon]: ../nomicon/index.html -/// [nomicon-soundness]: ../nomicon/safe-unsafe-meaning.html -/// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library -/// [Reference]: ../reference/unsafety.html -/// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696 -mod unsafe_keyword {} - -#[doc(keyword = "use")] -// -/// Import or rename items from other crates or modules, use values under ergonomic clones -/// semantic, or specify precise capturing with `use<..>`. -/// -/// ## Importing items -/// -/// The `use` keyword is employed to shorten the path required to refer to a module item. -/// The keyword may appear in modules, blocks, and even functions, typically at the top. -/// -/// The most basic usage of the keyword is `use path::to::item;`, -/// though a number of convenient shortcuts are supported: -/// -/// * Simultaneously binding a list of paths with a common prefix, -/// using the glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};` -/// * Simultaneously binding a list of paths with a common prefix and their common parent module, -/// using the [`self`] keyword, such as `use a::b::{self, c, d::e};` -/// * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. -/// This can also be used with the last two features: `use a::b::{self as ab, c as abc}`. -/// * Binding all paths matching a given prefix, -/// using the asterisk wildcard syntax `use a::b::*;`. -/// * Nesting groups of the previous features multiple times, -/// such as `use a::b::{self as ab, c, d::{*, e::f}};` -/// * Reexporting with visibility modifiers such as `pub use a::b;` -/// * Importing with `_` to only import the methods of a trait without binding it to a name -/// (to avoid conflict for example): `use ::std::io::Read as _;`. -/// -/// Using path qualifiers like [`crate`], [`super`] or [`self`] is supported: `use crate::a::b;`. -/// -/// Note that when the wildcard `*` is used on a type, it does not import its methods (though -/// for `enum`s it imports the variants, as shown in the example below). -/// -/// ```compile_fail,edition2018 -/// enum ExampleEnum { -/// VariantA, -/// VariantB, -/// } -/// -/// impl ExampleEnum { -/// fn new() -> Self { -/// Self::VariantA -/// } -/// } -/// -/// use ExampleEnum::*; -/// -/// // Compiles. -/// let _ = VariantA; -/// -/// // Does not compile! -/// let n = new(); -/// ``` -/// -/// For more information on `use` and paths in general, see the [Reference][ref-use-decls]. -/// -/// The differences about paths and the `use` keyword between the 2015 and 2018 editions -/// can also be found in the [Reference][ref-use-decls]. -/// -/// ## Precise capturing -/// -/// The `use<..>` syntax is used within certain `impl Trait` bounds to control which generic -/// parameters are captured. This is important for return-position `impl Trait` (RPIT) types, -/// as it affects borrow checking by controlling which generic parameters can be used in the -/// hidden type. -/// -/// For example, the following function demonstrates an error without precise capturing in -/// Rust 2021 and earlier editions: -/// -/// ```rust,compile_fail,edition2021 -/// fn f(x: &()) -> impl Sized { x } -/// ``` -/// -/// By using `use<'_>` for precise capturing, it can be resolved: -/// -/// ```rust -/// fn f(x: &()) -> impl Sized + use<'_> { x } -/// ``` -/// -/// This syntax specifies that the elided lifetime be captured and therefore available for -/// use in the hidden type. -/// -/// In Rust 2024, opaque types automatically capture all lifetime parameters in scope. -/// `use<..>` syntax serves as an important way of opting-out of that default. -/// -/// For more details about precise capturing, see the [Reference][ref-impl-trait]. -/// -/// ## Ergonomic clones -/// -/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the -/// value implements `UseCloned` or moving it otherwise. -/// -/// [`crate`]: keyword.crate.html -/// [`self`]: keyword.self.html -/// [`super`]: keyword.super.html -/// [ref-use-decls]: ../reference/items/use-declarations.html -/// [ref-impl-trait]: ../reference/types/impl-trait.html -mod use_keyword {} - -#[doc(keyword = "where")] -// -/// Add constraints that must be upheld to use an item. -/// -/// `where` allows specifying constraints on lifetime and generic parameters. -/// The [RFC] introducing `where` contains detailed information about the -/// keyword. -/// -/// # Examples -/// -/// `where` can be used for constraints with traits: -/// -/// ```rust -/// fn new() -> T { -/// T::default() -/// } -/// -/// fn new_where() -> T -/// where -/// T: Default, -/// { -/// T::default() -/// } -/// -/// assert_eq!(0.0, new()); -/// assert_eq!(0.0, new_where()); -/// -/// assert_eq!(0, new()); -/// assert_eq!(0, new_where()); -/// ``` -/// -/// `where` can also be used for lifetimes. -/// -/// This compiles because `longer` outlives `shorter`, thus the constraint is -/// respected: -/// -/// ```rust -/// fn select<'short, 'long>(s1: &'short str, s2: &'long str, second: bool) -> &'short str -/// where -/// 'long: 'short, -/// { -/// if second { s2 } else { s1 } -/// } -/// -/// let outer = String::from("Long living ref"); -/// let longer = &outer; -/// { -/// let inner = String::from("Short living ref"); -/// let shorter = &inner; -/// -/// assert_eq!(select(shorter, longer, false), shorter); -/// assert_eq!(select(shorter, longer, true), longer); -/// } -/// ``` -/// -/// On the other hand, this will not compile because the `where 'b: 'a` clause -/// is missing: the `'b` lifetime is not known to live at least as long as `'a` -/// which means this function cannot ensure it always returns a valid reference: -/// -/// ```rust,compile_fail -/// fn select<'a, 'b>(s1: &'a str, s2: &'b str, second: bool) -> &'a str -/// { -/// if second { s2 } else { s1 } -/// } -/// ``` -/// -/// `where` can also be used to express more complicated constraints that cannot -/// be written with the `` syntax: -/// -/// ```rust -/// fn first_or_default(mut i: I) -> I::Item -/// where -/// I: Iterator, -/// I::Item: Default, -/// { -/// i.next().unwrap_or_else(I::Item::default) -/// } -/// -/// assert_eq!(first_or_default([1, 2, 3].into_iter()), 1); -/// assert_eq!(first_or_default(Vec::::new().into_iter()), 0); -/// ``` -/// -/// `where` is available anywhere generic and lifetime parameters are available, -/// as can be seen with the [`Cow`](crate::borrow::Cow) type from the standard -/// library: -/// -/// ```rust -/// # #![allow(dead_code)] -/// pub enum Cow<'a, B> -/// where -/// B: ToOwned + ?Sized, -/// { -/// Borrowed(&'a B), -/// Owned(::Owned), -/// } -/// ``` -/// -/// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md -mod where_keyword {} - -#[doc(keyword = "while")] -// -/// Loop while a condition is upheld. -/// -/// A `while` expression is used for predicate loops. The `while` expression runs the conditional -/// expression before running the loop body, then runs the loop body if the conditional -/// expression evaluates to `true`, or exits the loop otherwise. -/// -/// ```rust -/// let mut counter = 0; -/// -/// while counter < 10 { -/// println!("{counter}"); -/// counter += 1; -/// } -/// ``` -/// -/// Like the [`for`] expression, we can use `break` and `continue`. A `while` expression -/// cannot break with a value and always evaluates to `()` unlike [`loop`]. -/// -/// ```rust -/// let mut i = 1; -/// -/// while i < 100 { -/// i *= 2; -/// if i == 64 { -/// break; // Exit when `i` is 64. -/// } -/// } -/// ``` -/// -/// As `if` expressions have their pattern matching variant in `if let`, so too do `while` -/// expressions with `while let`. The `while let` expression matches the pattern against the -/// expression, then runs the loop body if pattern matching succeeds, or exits the loop otherwise. -/// We can use `break` and `continue` in `while let` expressions just like in `while`. -/// -/// ```rust -/// let mut counter = Some(0); -/// -/// while let Some(i) = counter { -/// if i == 10 { -/// counter = None; -/// } else { -/// println!("{i}"); -/// counter = Some (i + 1); -/// } -/// } -/// ``` -/// -/// For more information on `while` and loops in general, see the [reference]. -/// -/// See also, [`for`], [`loop`]. -/// -/// [`for`]: keyword.for.html -/// [`loop`]: keyword.loop.html -/// [reference]: ../reference/expressions/loop-expr.html#predicate-loops -mod while_keyword {} - -// 2018 Edition keywords - -#[doc(alias = "promise")] -#[doc(keyword = "async")] -// -/// Returns a [`Future`] instead of blocking the current thread. -/// -/// Use `async` in front of `fn`, `closure`, or a `block` to turn the marked code into a `Future`. -/// As such the code will not be run immediately, but will only be evaluated when the returned -/// future is [`.await`]ed. -/// -/// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. -/// -/// ## Control Flow -/// [`return`] statements and [`?`][try operator] operators within `async` blocks do not cause -/// a return from the parent function; rather, they cause the `Future` returned by the block to -/// return with that value. -/// -/// For example, the following Rust function will return `5`, causing `x` to take the [`!` type][never type]: -/// ```rust -/// #[expect(unused_variables)] -/// fn example() -> i32 { -/// let x = { -/// return 5; -/// }; -/// } -/// ``` -/// In contrast, the following asynchronous function assigns a `Future` to `x`, and -/// only returns `5` when `x` is `.await`ed: -/// ```rust -/// async fn example() -> i32 { -/// let x = async { -/// return 5; -/// }; -/// -/// x.await -/// } -/// ``` -/// Code using `?` behaves similarly - it causes the `async` block to return a [`Result`] without -/// affecting the parent function. -/// -/// Note that you cannot use `break` or `continue` from within an `async` block to affect the -/// control flow of a loop in the parent function. -/// -/// Control flow in `async` blocks is documented further in the [async book][async book blocks]. -/// -/// ## Editions -/// -/// `async` is a keyword from the 2018 edition onwards. -/// -/// It is available for use in stable Rust from version 1.39 onwards. -/// -/// [`Future`]: future::Future -/// [`.await`]: ../std/keyword.await.html -/// [async book]: https://rust-lang.github.io/async-book/ -/// [`return`]: ../std/keyword.return.html -/// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try -/// [never type]: ../reference/types/never.html -/// [`Result`]: result::Result -/// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks -mod async_keyword {} - -#[doc(keyword = "await")] -// -/// Suspend execution until the result of a [`Future`] is ready. -/// -/// `.await`ing a future will suspend the current function's execution until the executor -/// has run the future to completion. -/// -/// Read the [async book] for details on how [`async`]/`await` and executors work. -/// -/// ## Editions -/// -/// `await` is a keyword from the 2018 edition onwards. -/// -/// It is available for use in stable Rust from version 1.39 onwards. -/// -/// [`Future`]: future::Future -/// [async book]: https://rust-lang.github.io/async-book/ -/// [`async`]: ../std/keyword.async.html -mod await_keyword {} - -#[doc(keyword = "dyn")] -// -/// `dyn` is a prefix of a [trait object]'s type. -/// -/// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait` -/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1]. -/// -/// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that -/// is being passed. That is, the type has been [erased]. -/// As such, a `dyn Trait` reference contains _two_ pointers. -/// One pointer goes to the data (e.g., an instance of a struct). -/// Another pointer goes to a map of method call names to function pointers -/// (known as a virtual method table or vtable). -/// -/// At run-time, when a method needs to be called on the `dyn Trait`, the vtable is consulted to get -/// the function pointer and then that function pointer is called. -/// -/// See the Reference for more information on [trait objects][ref-trait-obj] -/// and [dyn compatibility][ref-dyn-compat]. -/// -/// ## Trade-offs -/// -/// The above indirection is the additional runtime cost of calling a function on a `dyn Trait`. -/// Methods called by dynamic dispatch generally cannot be inlined by the compiler. -/// -/// However, `dyn Trait` is likely to produce smaller code than `impl Trait` / generic parameters as -/// the method won't be duplicated for each concrete type. -/// -/// [trait object]: ../book/ch17-02-trait-objects.html -/// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch -/// [ref-trait-obj]: ../reference/types/trait-object.html -/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility -/// [erased]: https://en.wikipedia.org/wiki/Type_erasure -/// [^1]: Formerly known as *object safe*. -mod dyn_keyword {} - -#[doc(keyword = "union")] -// -/// The [Rust equivalent of a C-style union][union]. -/// -/// A `union` looks like a [`struct`] in terms of declaration, but all of its -/// fields exist in the same memory, superimposed over one another. For instance, -/// if we wanted some bits in memory that we sometimes interpret as a `u32` and -/// sometimes as an `f32`, we could write: -/// -/// ```rust -/// union IntOrFloat { -/// i: u32, -/// f: f32, -/// } -/// -/// let mut u = IntOrFloat { f: 1.0 }; -/// // Reading the fields of a union is always unsafe -/// assert_eq!(unsafe { u.i }, 1065353216); -/// // Updating through any of the field will modify all of them -/// u.i = 1073741824; -/// assert_eq!(unsafe { u.f }, 2.0); -/// ``` -/// -/// # Matching on unions -/// -/// It is possible to use pattern matching on `union`s. A single field name must -/// be used and it must match the name of one of the `union`'s field. -/// Like reading from a `union`, pattern matching on a `union` requires `unsafe`. -/// -/// ```rust -/// union IntOrFloat { -/// i: u32, -/// f: f32, -/// } -/// -/// let u = IntOrFloat { f: 1.0 }; -/// -/// unsafe { -/// match u { -/// IntOrFloat { i: 10 } => println!("Found exactly ten!"), -/// // Matching the field `f` provides an `f32`. -/// IntOrFloat { f } => println!("Found f = {f} !"), -/// } -/// } -/// ``` -/// -/// # References to union fields -/// -/// All fields in a `union` are all at the same place in memory which means -/// borrowing one borrows the entire `union`, for the same lifetime: -/// -/// ```rust,compile_fail,E0502 -/// union IntOrFloat { -/// i: u32, -/// f: f32, -/// } -/// -/// let mut u = IntOrFloat { f: 1.0 }; -/// -/// let f = unsafe { &u.f }; -/// // This will not compile because the field has already been borrowed, even -/// // if only immutably -/// let i = unsafe { &mut u.i }; -/// -/// *i = 10; -/// println!("f = {f} and i = {i}"); -/// ``` -/// -/// See the [Reference][union] for more information on `union`s. -/// -/// [`struct`]: keyword.struct.html -/// [union]: ../reference/items/unions.html -mod union_keyword {} diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs new file mode 120000 index 0000000..4e741bd --- /dev/null +++ b/library/std/src/keyword_docs.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/keyword_docs.rs \ No newline at end of file diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs deleted file mode 100644 index 6fcb28e..0000000 --- a/library/std/src/lib.rs +++ /dev/null @@ -1,766 +0,0 @@ -//! # The Rust Standard Library -//! -//! The Rust Standard Library is the foundation of portable Rust software, a -//! set of minimal and battle-tested shared abstractions for the [broader Rust -//! ecosystem][crates.io]. It offers core types, like [`Vec`] and -//! [`Option`], library-defined [operations on language -//! primitives](#primitives), [standard macros](#macros), [I/O] and -//! [multithreading], among [many other things][other]. -//! -//! `std` is available to all Rust crates by default. Therefore, the -//! standard library can be accessed in [`use`] statements through the path -//! `std`, as in [`use std::env`]. -//! -//! # How to read this documentation -//! -//! If you already know the name of what you are looking for, the fastest way to -//! find it is to use the search -//! button at the top of the page. -//! -//! Otherwise, you may want to jump to one of these useful sections: -//! -//! * [`std::*` modules](#modules) -//! * [Primitive types](#primitives) -//! * [Standard macros](#macros) -//! * [The Rust Prelude] -//! -//! If this is your first time, the documentation for the standard library is -//! written to be casually perused. Clicking on interesting things should -//! generally lead you to interesting places. Still, there are important bits -//! you don't want to miss, so read on for a tour of the standard library and -//! its documentation! -//! -//! Once you are familiar with the contents of the standard library you may -//! begin to find the verbosity of the prose distracting. At this stage in your -//! development you may want to press the -//! " Summary" -//! button near the top of the page to collapse it into a more skimmable view. -//! -//! While you are looking at the top of the page, also notice the -//! "Source" link. Rust's API documentation comes with the source -//! code and you are encouraged to read it. The standard library source is -//! generally high quality and a peek behind the curtains is -//! often enlightening. -//! -//! # What is in the standard library documentation? -//! -//! First of all, The Rust Standard Library is divided into a number of focused -//! modules, [all listed further down this page](#modules). These modules are -//! the bedrock upon which all of Rust is forged, and they have mighty names -//! like [`std::slice`] and [`std::cmp`]. Modules' documentation typically -//! includes an overview of the module along with examples, and are a smart -//! place to start familiarizing yourself with the library. -//! -//! Second, implicit methods on [primitive types] are documented here. This can -//! be a source of confusion for two reasons: -//! -//! 1. While primitives are implemented by the compiler, the standard library -//! implements methods directly on the primitive types (and it is the only -//! library that does so), which are [documented in the section on -//! primitives](#primitives). -//! 2. The standard library exports many modules *with the same name as -//! primitive types*. These define additional items related to the primitive -//! type, but not the all-important methods. -//! -//! So for example there is a [page for the primitive type -//! `char`](primitive::char) that lists all the methods that can be called on -//! characters (very useful), and there is a [page for the module -//! `std::char`](crate::char) that documents iterator and error types created by these methods -//! (rarely useful). -//! -//! Note the documentation for the primitives [`str`] and [`[T]`][prim@slice] (also -//! called 'slice'). Many method calls on [`String`] and [`Vec`] are actually -//! calls to methods on [`str`] and [`[T]`][prim@slice] respectively, via [deref -//! coercions][deref-coercions]. -//! -//! Third, the standard library defines [The Rust Prelude], a small collection -//! of items - mostly traits - that are imported into every module of every -//! crate. The traits in the prelude are pervasive, making the prelude -//! documentation a good entry point to learning about the library. -//! -//! And finally, the standard library exports a number of standard macros, and -//! [lists them on this page](#macros) (technically, not all of the standard -//! macros are defined by the standard library - some are defined by the -//! compiler - but they are documented here the same). Like the prelude, the -//! standard macros are imported by default into all crates. -//! -//! # Contributing changes to the documentation -//! -//! Check out the Rust contribution guidelines [here]( -//! https://rustc-dev-guide.rust-lang.org/contributing.html#writing-documentation). -//! The source for this documentation can be found on -//! [GitHub](https://github.com/rust-lang/rust) in the 'library/std/' directory. -//! To contribute changes, make sure you read the guidelines first, then submit -//! pull-requests for your suggested changes. -//! -//! Contributions are appreciated! If you see a part of the docs that can be -//! improved, submit a PR, or chat with us first on [Zulip][rust-zulip] -//! #docs. -//! -//! # A Tour of The Rust Standard Library -//! -//! The rest of this crate documentation is dedicated to pointing out notable -//! features of The Rust Standard Library. -//! -//! ## Containers and collections -//! -//! The [`option`] and [`result`] modules define optional and error-handling -//! types, [`Option`] and [`Result`]. The [`iter`] module defines -//! Rust's iterator trait, [`Iterator`], which works with the [`for`] loop to -//! access collections. -//! -//! The standard library exposes three common ways to deal with contiguous -//! regions of memory: -//! -//! * [`Vec`] - A heap-allocated *vector* that is resizable at runtime. -//! * [`[T; N]`][prim@array] - An inline *array* with a fixed size at compile time. -//! * [`[T]`][prim@slice] - A dynamically sized *slice* into any other kind of contiguous -//! storage, whether heap-allocated or not. -//! -//! Slices can only be handled through some kind of *pointer*, and as such come -//! in many flavors such as: -//! -//! * `&[T]` - *shared slice* -//! * `&mut [T]` - *mutable slice* -//! * [`Box<[T]>`][owned slice] - *owned slice* -//! -//! [`str`], a UTF-8 string slice, is a primitive type, and the standard library -//! defines many methods for it. Rust [`str`]s are typically accessed as -//! immutable references: `&str`. Use the owned [`String`] for building and -//! mutating strings. -//! -//! For converting to strings use the [`format!`] macro, and for converting from -//! strings use the [`FromStr`] trait. -//! -//! Data may be shared by placing it in a reference-counted box or the [`Rc`] -//! type, and if further contained in a [`Cell`] or [`RefCell`], may be mutated -//! as well as shared. Likewise, in a concurrent setting it is common to pair an -//! atomically-reference-counted box, [`Arc`], with a [`Mutex`] to get the same -//! effect. -//! -//! The [`collections`] module defines maps, sets, linked lists and other -//! typical collection types, including the common [`HashMap`]. -//! -//! ## Platform abstractions and I/O -//! -//! Besides basic data types, the standard library is largely concerned with -//! abstracting over differences in common platforms, most notably Windows and -//! Unix derivatives. -//! -//! Common types of I/O, including [files], [TCP], and [UDP], are defined in -//! the [`io`], [`fs`], and [`net`] modules. -//! -//! The [`thread`] module contains Rust's threading abstractions. [`sync`] -//! contains further primitive shared memory types, including [`atomic`], [`mpmc`] and -//! [`mpsc`], which contains the channel types for message passing. -//! -//! # Use before and after `main()` -//! -//! Many parts of the standard library are expected to work before and after `main()`; -//! but this is not guaranteed or ensured by tests. It is recommended that you write your own tests -//! and run them on each platform you wish to support. -//! This means that use of `std` before/after main, especially of features that interact with the -//! OS or global state, is exempted from stability and portability guarantees and instead only -//! provided on a best-effort basis. Nevertheless bug reports are appreciated. -//! -//! On the other hand `core` and `alloc` are most likely to work in such environments with -//! the caveat that any hookable behavior such as panics, oom handling or allocators will also -//! depend on the compatibility of the hooks. -//! -//! Some features may also behave differently outside main, e.g. stdio could become unbuffered, -//! some panics might turn into aborts, backtraces might not get symbolicated or similar. -//! -//! Non-exhaustive list of known limitations: -//! -//! - after-main use of thread-locals, which also affects additional features: -//! - [`thread::current()`] -//! - under UNIX, before main, file descriptors 0, 1, and 2 may be unchanged -//! (they are guaranteed to be open during main, -//! and are opened to /dev/null O_RDWR if they weren't open on program start) -//! -//! -//! [I/O]: io -//! [TCP]: net::TcpStream -//! [The Rust Prelude]: prelude -//! [UDP]: net::UdpSocket -//! [`Arc`]: sync::Arc -//! [owned slice]: boxed -//! [`Cell`]: cell::Cell -//! [`FromStr`]: str::FromStr -//! [`HashMap`]: collections::HashMap -//! [`Mutex`]: sync::Mutex -//! [`Option`]: option::Option -//! [`Rc`]: rc::Rc -//! [`RefCell`]: cell::RefCell -//! [`Result`]: result::Result -//! [`Vec`]: vec::Vec -//! [`atomic`]: sync::atomic -//! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for -//! [`str`]: prim@str -//! [`mpmc`]: sync::mpmc -//! [`mpsc`]: sync::mpsc -//! [`std::cmp`]: cmp -//! [`std::slice`]: mod@slice -//! [`use std::env`]: env/index.html -//! [`use`]: ../book/ch07-02-defining-modules-to-control-scope-and-privacy.html -//! [crates.io]: https://crates.io -//! [deref-coercions]: ../book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods -//! [files]: fs::File -//! [multithreading]: thread -//! [other]: #what-is-in-the-standard-library-documentation -//! [primitive types]: ../book/ch03-02-data-types.html -//! [rust-zulip]: https://rust-lang.zulipchat.com/ -//! [array]: prim@array -//! [slice]: prim@slice - -#![cfg_attr(not(restricted_std), stable(feature = "rust1", since = "1.0.0"))] -#![cfg_attr( - restricted_std, - unstable( - feature = "restricted_std", - issue = "none", - reason = "You have attempted to use a standard library built for a platform that it doesn't \ - know how to support. Consider building it for a known environment, disabling it with \ - `#![no_std]` or overriding this warning by enabling this feature." - ) -)] -#![rustc_preserve_ub_checks] -#![doc( - html_playground_url = "https://play.rust-lang.org/", - issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) -)] -#![doc(rust_logo)] -#![doc(auto_cfg(hide(no_global_oom_handling)))] -// Don't link to std. We are std. -#![no_std] -// Tell the compiler to link to either panic_abort or panic_unwind -#![needs_panic_runtime] -// -// Lints: -#![warn(deprecated_in_future)] -#![warn(missing_docs)] -#![warn(missing_debug_implementations)] -#![allow(explicit_outlives_requirements)] -#![allow(unused_lifetimes)] -#![allow(internal_features)] -#![deny(fuzzy_provenance_casts)] -#![deny(unsafe_op_in_unsafe_fn)] -#![allow(rustdoc::redundant_explicit_links)] -#![warn(rustdoc::unescaped_backticks)] -// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` -#![deny(ffi_unwind_calls)] -// std may use features in a platform-specific way -#![allow(unused_features)] -// -// Features: -#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))] -#![cfg_attr( - all(target_vendor = "fortanix", target_env = "sgx"), - feature(slice_index_methods, coerce_unsized, sgx_platform) -)] -#![cfg_attr(all(test, target_os = "uefi"), feature(uefi_std))] -#![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] -#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] -// -// Language features: -// tidy-alphabetical-start -#![feature(alloc_error_handler)] -#![feature(allocator_internals)] -#![feature(allow_internal_unsafe)] -#![feature(allow_internal_unstable)] -#![feature(asm_experimental_arch)] -#![feature(autodiff)] -#![feature(cfg_sanitizer_cfi)] -#![feature(cfg_target_thread_local)] -#![feature(cfi_encoding)] -#![feature(const_default)] -#![feature(const_trait_impl)] -#![feature(core_float_math)] -#![feature(decl_macro)] -#![feature(deprecated_suggestion)] -#![feature(doc_cfg)] -#![feature(doc_masked)] -#![feature(doc_notable_trait)] -#![feature(dropck_eyepatch)] -#![feature(f16)] -#![feature(f128)] -#![feature(ffi_const)] -#![feature(formatting_options)] -#![feature(funnel_shifts)] -#![feature(intra_doc_pointers)] -#![feature(iter_advance_by)] -#![feature(iter_next_chunk)] -#![feature(lang_items)] -#![feature(link_cfg)] -#![feature(linkage)] -#![feature(macro_metavar_expr_concat)] -#![feature(maybe_uninit_fill)] -#![feature(min_specialization)] -#![feature(must_not_suspend)] -#![feature(needs_panic_runtime)] -#![feature(negative_impls)] -#![feature(never_type)] -#![feature(optimize_attribute)] -#![feature(prelude_import)] -#![feature(rustc_attrs)] -#![feature(rustdoc_internals)] -#![feature(staged_api)] -#![feature(stmt_expr_attributes)] -#![feature(strict_provenance_lints)] -#![feature(target_feature_inline_always)] -#![feature(thread_local)] -#![feature(try_blocks)] -#![feature(try_trait_v2)] -#![feature(type_alias_impl_trait)] -#![feature(uint_carryless_mul)] -// tidy-alphabetical-end -// -// Library features (core): -// tidy-alphabetical-start -#![feature(bstr)] -#![feature(bstr_internals)] -#![feature(cast_maybe_uninit)] -#![feature(char_internals)] -#![feature(clone_to_uninit)] -#![feature(const_convert)] -#![feature(core_intrinsics)] -#![feature(core_io_borrowed_buf)] -#![feature(cstr_display)] -#![feature(drop_guard)] -#![feature(duration_constants)] -#![feature(error_generic_member_access)] -#![feature(error_iter)] -#![feature(exact_size_is_empty)] -#![feature(exclusive_wrapper)] -#![feature(extend_one)] -#![feature(float_algebraic)] -#![feature(float_gamma)] -#![feature(float_minimum_maximum)] -#![feature(fmt_internals)] -#![feature(fn_ptr_trait)] -#![feature(generic_atomic)] -#![feature(hasher_prefixfree_extras)] -#![feature(hashmap_internals)] -#![feature(hint_must_use)] -#![feature(int_from_ascii)] -#![feature(ip)] -#![feature(maybe_uninit_array_assume_init)] -#![feature(panic_can_unwind)] -#![feature(panic_internals)] -#![feature(pin_coerce_unsized_trait)] -#![feature(pointer_is_aligned_to)] -#![feature(portable_simd)] -#![feature(ptr_as_uninit)] -#![feature(ptr_mask)] -#![feature(random)] -#![feature(slice_internals)] -#![feature(slice_ptr_get)] -#![feature(slice_range)] -#![feature(slice_split_once)] -#![feature(std_internals)] -#![feature(str_internals)] -#![feature(sync_unsafe_cell)] -#![feature(temporary_niche_types)] -#![feature(ub_checks)] -#![feature(used_with_arg)] -// tidy-alphabetical-end -// -// Library features (alloc): -// tidy-alphabetical-start -#![feature(allocator_api)] -#![feature(clone_from_ref)] -#![feature(get_mut_unchecked)] -#![feature(map_try_insert)] -#![feature(slice_concat_trait)] -#![feature(thin_box)] -#![feature(try_reserve_kind)] -#![feature(try_with_capacity)] -#![feature(unique_rc_arc)] -#![feature(wtf8_internals)] -// tidy-alphabetical-end -// -// Library features (unwind): -// tidy-alphabetical-start -#![feature(panic_unwind)] -// tidy-alphabetical-end -// -// Library features (std_detect): -// tidy-alphabetical-start -#![feature(stdarch_internal)] -// tidy-alphabetical-end -// -// Only for re-exporting: -// tidy-alphabetical-start -#![feature(async_iterator)] -#![feature(c_variadic)] -#![feature(cfg_accessible)] -#![feature(cfg_eval)] -#![feature(concat_bytes)] -#![feature(const_format_args)] -#![feature(custom_test_frameworks)] -#![feature(edition_panic)] -#![feature(format_args_nl)] -#![feature(log_syntax)] -#![feature(test)] -#![feature(trace_macros)] -// tidy-alphabetical-end -// -// Only used in tests/benchmarks: -// -// Only for const-ness: -// tidy-alphabetical-start -#![feature(io_const_error)] -// tidy-alphabetical-end -// -#![default_lib_allocator] - -// The Rust prelude -// The compiler expects the prelude definition to be defined before its use statement. -pub mod prelude; - -// Explicitly import the prelude. The compiler uses this same unstable attribute -// to import the prelude implicitly when building crates that depend on std. -#[prelude_import] -#[allow(unused)] -use prelude::rust_2024::*; - -// Access to Bencher, etc. -#[cfg(test)] -extern crate test; - -#[allow(unused_imports)] // macros from `alloc` are not used on all platforms -#[macro_use] -extern crate alloc as alloc_crate; - -// Many compiler tests depend on libc being pulled in by std -// so include it here even if it's unused. -#[doc(masked)] -#[allow(unused_extern_crates)] -#[cfg(not(all(windows, target_env = "msvc")))] -extern crate libc; - -// We always need an unwinder currently for backtraces -#[doc(masked)] -#[allow(unused_extern_crates)] -extern crate unwind; - -// FIXME: #94122 this extern crate definition only exist here to stop -// miniz_oxide docs leaking into std docs. Find better way to do it. -// Remove exclusion from tidy platform check when this removed. -#[doc(masked)] -#[allow(unused_extern_crates)] -#[cfg(all( - not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))), - feature = "miniz_oxide" -))] -extern crate miniz_oxide; - -// During testing, this crate is not actually the "real" std library, but rather -// it links to the real std library, which was compiled from this same source -// code. So any lang items std defines are conditionally excluded (or else they -// would generate duplicate lang item errors), and any globals it defines are -// _not_ the globals used by "real" std. So this import, defined only during -// testing gives test-std access to real-std lang items and globals. See #2912 -#[cfg(test)] -extern crate std as realstd; - -// The standard macros that are not built-in to the compiler. -#[macro_use] -#[doc(hidden)] -#[unstable(feature = "std_internals", issue = "none")] -pub mod macros; - -// The runtime entry point and a few unstable public functions used by the -// compiler -#[macro_use] -pub mod rt; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::any; -#[stable(feature = "core_array", since = "1.35.0")] -pub use core::array; -#[unstable(feature = "async_iterator", issue = "79024")] -pub use core::async_iter; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::cell; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::char; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::clone; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::cmp; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::convert; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::default; -#[unstable(feature = "field_projections", issue = "145383")] -pub use core::field; -#[stable(feature = "futures_api", since = "1.36.0")] -pub use core::future; -#[stable(feature = "core_hint", since = "1.27.0")] -pub use core::hint; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::i8; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::i16; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::i32; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::i64; -#[stable(feature = "i128", since = "1.26.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::i128; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::intrinsics; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::isize; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::iter; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::marker; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::mem; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::ops; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::option; -#[stable(feature = "pin", since = "1.33.0")] -pub use core::pin; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::ptr; -#[unstable(feature = "new_range_api", issue = "125687")] -pub use core::range; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::result; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::u8; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::u16; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::u32; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::u64; -#[stable(feature = "i128", since = "1.26.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::u128; -#[unstable(feature = "unsafe_binders", issue = "130516")] -pub use core::unsafe_binder; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::usize; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::borrow; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::boxed; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::fmt; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::format; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::rc; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::slice; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::str; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::string; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::vec; - -#[path = "num/f128.rs"] -pub mod f128; -#[path = "num/f16.rs"] -pub mod f16; -#[path = "num/f32.rs"] -pub mod f32; -#[path = "num/f64.rs"] -pub mod f64; - -#[macro_use] -pub mod thread; -pub mod ascii; -pub mod backtrace; -#[unstable(feature = "bstr", issue = "134915")] -pub mod bstr; -pub mod collections; -pub mod env; -pub mod error; -pub mod ffi; -pub mod fs; -pub mod hash; -pub mod io; -pub mod net; -pub mod num; -pub mod os; -pub mod panic; -#[unstable(feature = "pattern_type_macro", issue = "123646")] -pub mod pat; -pub mod path; -pub mod process; -#[unstable(feature = "random", issue = "130703")] -pub mod random; -pub mod sync; -pub mod time; - -// Pull in `std_float` crate into std. The contents of -// `std_float` are in a different repository: rust-lang/portable-simd. -#[path = "../../portable-simd/crates/std_float/src/lib.rs"] -#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn)] -#[allow(rustdoc::bare_urls)] -#[unstable(feature = "portable_simd", issue = "86656")] -mod std_float; - -#[unstable(feature = "portable_simd", issue = "86656")] -pub mod simd { - #![doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")] - - #[doc(inline)] - pub use core::simd::*; - - #[doc(inline)] - pub use crate::std_float::StdFloat; -} - -#[unstable(feature = "autodiff", issue = "124509")] -/// This module provides support for automatic differentiation. -pub mod autodiff { - /// This macro handles automatic differentiation. - pub use core::autodiff::{autodiff_forward, autodiff_reverse}; -} - -#[stable(feature = "futures_api", since = "1.36.0")] -pub mod task { - //! Types and Traits for working with asynchronous tasks. - - #[doc(inline)] - #[stable(feature = "wake_trait", since = "1.51.0")] - pub use alloc::task::*; - #[doc(inline)] - #[stable(feature = "futures_api", since = "1.36.0")] - pub use core::task::*; -} - -#[doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")] -#[stable(feature = "simd_arch", since = "1.27.0")] -pub mod arch { - #[stable(feature = "simd_arch", since = "1.27.0")] - // The `no_inline`-attribute is required to make the documentation of all - // targets available. - // See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for - // more information. - #[doc(no_inline)] // Note (#82861): required for correct documentation - pub use core::arch::*; - - #[stable(feature = "simd_aarch64", since = "1.60.0")] - pub use std_detect::is_aarch64_feature_detected; - #[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")] - pub use std_detect::is_arm_feature_detected; - #[unstable(feature = "is_loongarch_feature_detected", issue = "117425")] - pub use std_detect::is_loongarch_feature_detected; - #[unstable(feature = "is_riscv_feature_detected", issue = "111192")] - pub use std_detect::is_riscv_feature_detected; - #[stable(feature = "stdarch_s390x_feature_detection", since = "1.93.0")] - pub use std_detect::is_s390x_feature_detected; - #[stable(feature = "simd_x86", since = "1.27.0")] - pub use std_detect::is_x86_feature_detected; - #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] - pub use std_detect::{is_mips_feature_detected, is_mips64_feature_detected}; - #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] - pub use std_detect::{is_powerpc_feature_detected, is_powerpc64_feature_detected}; -} - -// This was stabilized in the crate root so we have to keep it there. -#[stable(feature = "simd_x86", since = "1.27.0")] -pub use std_detect::is_x86_feature_detected; - -mod sys; - -pub mod alloc; - -// Private support modules -mod panicking; - -#[path = "../../backtrace/src/lib.rs"] -#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)] -mod backtrace_rs; - -#[stable(feature = "cfg_select", since = "1.95.0")] -pub use core::cfg_select; -#[unstable( - feature = "concat_bytes", - issue = "87555", - reason = "`concat_bytes` is not stable enough for use and is subject to change" -)] -pub use core::concat_bytes; -#[stable(feature = "matches_macro", since = "1.42.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::matches; -#[stable(feature = "core_primitive", since = "1.43.0")] -pub use core::primitive; -#[stable(feature = "todo_macro", since = "1.40.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::todo; -// Re-export built-in macros defined through core. -#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -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, -}; -// Re-export macros defined in core. -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated, deprecated_in_future)] -pub use core::{ - assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, r#try, unimplemented, - unreachable, write, writeln, -}; -#[stable(feature = "assert_matches", since = "1.95.0")] -pub use core::{assert_matches, debug_assert_matches}; - -// Re-export unstable derive macro defined through core. -#[unstable(feature = "derive_from", issue = "144889")] -/// Unstable module containing the unstable `From` derive macro. -pub mod from { - #[unstable(feature = "derive_from", issue = "144889")] - pub use core::from::From; -} - -// Include a number of private modules that exist solely to provide -// the rustdoc documentation for primitive types. Using `include!` -// because rustdoc only looks for these modules at the crate level. -include!("../../core/src/primitive_docs.rs"); - -// Include a number of private modules that exist solely to provide -// the rustdoc documentation for the existing keywords. Using `include!` -// because rustdoc only looks for these modules at the crate level. -include!("keyword_docs.rs"); - -// This is required to avoid an unstable error when `restricted-std` is not -// enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std -// is unconditional, so the unstable feature needs to be defined somewhere. -#[unstable(feature = "restricted_std", issue = "none")] -mod __restricted_std_workaround {} - -mod sealed { - /// This trait being unreachable from outside the crate - /// prevents outside implementations of our extension traits. - /// This allows adding more trait methods in the future. - #[unstable(feature = "sealed", issue = "none")] - pub trait Sealed {} -} - -#[cfg(test)] -#[allow(dead_code)] // Not used in all configurations. -pub(crate) mod test_helpers; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs new file mode 120000 index 0000000..25aff23 --- /dev/null +++ b/library/std/src/lib.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/lib.rs \ No newline at end of file diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs deleted file mode 100644 index 0bb1455..0000000 --- a/library/std/src/macros.rs +++ /dev/null @@ -1,416 +0,0 @@ -//! 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 - -#[doc = include_str!("../../core/src/macros/panic.md")] -#[macro_export] -#[rustc_builtin_macro(std_panic)] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable(edition_panic)] -#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")] -macro_rules! panic { - // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` - // depending on the edition of the caller. - ($($arg:tt)*) => { - /* compiler built-in */ - }; -} - -/// Prints to the standard output. -/// -/// Equivalent to the [`println!`] macro except that a newline is not printed at -/// the end of the message. -/// -/// Note that stdout is frequently line-buffered by default so it may be -/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted -/// immediately. -/// -/// The `print!` macro will lock the standard output on each call. If you call -/// `print!` within a hot loop, this behavior may be the bottleneck of the loop. -/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]: -/// ``` -/// use std::io::{stdout, Write}; -/// -/// let mut lock = stdout().lock(); -/// write!(lock, "hello world").unwrap(); -/// ``` -/// -/// Use `print!` only for the primary output of your program. Use -/// [`eprint!`] instead to print error and progress messages. -/// -/// See the formatting documentation in [`std::fmt`](crate::fmt) -/// for details of the macro argument syntax. -/// -/// [flush]: crate::io::Write::flush -/// [`println!`]: crate::println -/// [`eprint!`]: crate::eprint -/// [lock]: crate::io::Stdout -/// -/// # Panics -/// -/// Panics if writing to `io::stdout()` fails. -/// -/// Writing to non-blocking stdout can cause an error, which will lead -/// this macro to panic. -/// -/// # Examples -/// -/// ``` -/// use std::io::{self, Write}; -/// -/// print!("this "); -/// print!("will "); -/// print!("be "); -/// print!("on "); -/// print!("the "); -/// print!("same "); -/// print!("line "); -/// -/// io::stdout().flush().unwrap(); -/// -/// print!("this string has a newline, why not choose println! instead?\n"); -/// -/// io::stdout().flush().unwrap(); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")] -#[allow_internal_unstable(print_internals)] -macro_rules! print { - ($($arg:tt)*) => {{ - $crate::io::_print($crate::format_args!($($arg)*)); - }}; -} - -/// Prints to the standard output, with a newline. -/// -/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone -/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)). -/// -/// This macro uses the same syntax as [`format!`], but writes to the standard output instead. -/// See [`std::fmt`] for more information. -/// -/// The `println!` macro will lock the standard output on each call. If you call -/// `println!` within a hot loop, this behavior may be the bottleneck of the loop. -/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]: -/// ``` -/// use std::io::{stdout, Write}; -/// -/// let mut lock = stdout().lock(); -/// writeln!(lock, "hello world").unwrap(); -/// ``` -/// -/// Use `println!` only for the primary output of your program. Use -/// [`eprintln!`] instead to print error and progress messages. -/// -/// See the formatting documentation in [`std::fmt`](crate::fmt) -/// for details of the macro argument syntax. -/// -/// [`std::fmt`]: crate::fmt -/// [`eprintln!`]: crate::eprintln -/// [lock]: crate::io::Stdout -/// -/// # Panics -/// -/// Panics if writing to [`io::stdout`] fails. -/// -/// Writing to non-blocking stdout can cause an error, which will lead -/// this macro to panic. -/// -/// [`io::stdout`]: crate::io::stdout -/// -/// # Examples -/// -/// ``` -/// println!(); // prints just a newline -/// println!("hello there!"); -/// println!("format {} arguments", "some"); -/// let local_variable = "some"; -/// println!("format {local_variable} arguments"); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")] -#[allow_internal_unstable(print_internals, format_args_nl)] -macro_rules! println { - () => { - $crate::print!("\n") - }; - ($($arg:tt)*) => {{ - $crate::io::_print($crate::format_args_nl!($($arg)*)); - }}; -} - -/// Prints to the standard error. -/// -/// Equivalent to the [`print!`] macro, except that output goes to -/// [`io::stderr`] instead of [`io::stdout`]. See [`print!`] for -/// example usage. -/// -/// Use `eprint!` only for error and progress messages. Use `print!` -/// instead for the primary output of your program. -/// -/// [`io::stderr`]: crate::io::stderr -/// [`io::stdout`]: crate::io::stdout -/// -/// See the formatting documentation in [`std::fmt`](crate::fmt) -/// for details of the macro argument syntax. -/// -/// # Panics -/// -/// Panics if writing to `io::stderr` fails. -/// -/// Writing to non-blocking stderr can cause an error, which will lead -/// this macro to panic. -/// -/// # Examples -/// -/// ``` -/// eprint!("Error: Could not complete task"); -/// ``` -#[macro_export] -#[stable(feature = "eprint", since = "1.19.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")] -#[allow_internal_unstable(print_internals)] -macro_rules! eprint { - ($($arg:tt)*) => {{ - $crate::io::_eprint($crate::format_args!($($arg)*)); - }}; -} - -/// Prints to the standard error, with a newline. -/// -/// Equivalent to the [`println!`] macro, except that output goes to -/// [`io::stderr`] instead of [`io::stdout`]. See [`println!`] for -/// example usage. -/// -/// Use `eprintln!` only for error and progress messages. Use `println!` -/// instead for the primary output of your program. -/// -/// See the formatting documentation in [`std::fmt`](crate::fmt) -/// for details of the macro argument syntax. -/// -/// [`io::stderr`]: crate::io::stderr -/// [`io::stdout`]: crate::io::stdout -/// [`println!`]: crate::println -/// -/// # Panics -/// -/// Panics if writing to `io::stderr` fails. -/// -/// Writing to non-blocking stderr can cause an error, which will lead -/// this macro to panic. -/// -/// # Examples -/// -/// ``` -/// eprintln!("Error: Could not complete task"); -/// ``` -#[macro_export] -#[stable(feature = "eprint", since = "1.19.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")] -#[allow_internal_unstable(print_internals, format_args_nl)] -macro_rules! eprintln { - () => { - $crate::eprint!("\n") - }; - ($($arg:tt)*) => {{ - $crate::io::_eprint($crate::format_args_nl!($($arg)*)); - }}; -} - -/// Prints and returns the value of a given expression for quick and dirty -/// debugging. -/// -/// An example: -/// -/// ```rust -/// let a = 2; -/// let b = dbg!(a * 2) + 1; -/// // ^-- prints: [src/main.rs:2:9] a * 2 = 4 -/// assert_eq!(b, 5); -/// ``` -/// -/// The macro works by using the `Debug` implementation of the type of -/// the given expression to print the value to [stderr] along with the -/// source location of the macro invocation as well as the source code -/// of the expression. -/// -/// Invoking the macro on an expression moves and takes ownership of it -/// before returning the evaluated expression unchanged. If the type -/// of the expression does not implement `Copy` and you don't want -/// to give up ownership, you can instead borrow with `dbg!(&expr)` -/// for some expression `expr`. -/// -/// The `dbg!` macro works exactly the same in release builds. -/// This is useful when debugging issues that only occur in release -/// builds or when debugging in release mode is significantly faster. -/// -/// Note that the macro is intended as a debugging tool and therefore you -/// should avoid having uses of it in version control for long periods -/// (other than in tests and similar). -/// Debug output from production code is better done with other facilities -/// such as the [`debug!`] macro from the [`log`] crate. -/// -/// # Stability -/// -/// The exact output printed by this macro should not be relied upon -/// and is subject to future changes. -/// -/// # Panics -/// -/// Panics if writing to `io::stderr` fails. -/// -/// # Further examples -/// -/// With a method call: -/// -/// ```rust -/// fn foo(n: usize) { -/// if let Some(_) = dbg!(n.checked_sub(4)) { -/// // ... -/// } -/// } -/// -/// foo(3) -/// ``` -/// -/// This prints to [stderr]: -/// -/// ```text,ignore -/// [src/main.rs:2:22] n.checked_sub(4) = None -/// ``` -/// -/// Naive factorial implementation: -/// -/// ```rust -/// fn factorial(n: u32) -> u32 { -/// if dbg!(n <= 1) { -/// dbg!(1) -/// } else { -/// dbg!(n * factorial(n - 1)) -/// } -/// } -/// -/// dbg!(factorial(4)); -/// ``` -/// -/// This prints to [stderr]: -/// -/// ```text,ignore -/// [src/main.rs:2:8] n <= 1 = false -/// [src/main.rs:2:8] n <= 1 = false -/// [src/main.rs:2:8] n <= 1 = false -/// [src/main.rs:2:8] n <= 1 = true -/// [src/main.rs:3:9] 1 = 1 -/// [src/main.rs:7:9] n * factorial(n - 1) = 2 -/// [src/main.rs:7:9] n * factorial(n - 1) = 6 -/// [src/main.rs:7:9] n * factorial(n - 1) = 24 -/// [src/main.rs:9:1] factorial(4) = 24 -/// ``` -/// -/// The `dbg!(..)` macro moves the input: -/// -/// ```compile_fail -/// /// A wrapper around `usize` which importantly is not Copyable. -/// #[derive(Debug)] -/// struct NoCopy(usize); -/// -/// let a = NoCopy(42); -/// let _ = dbg!(a); // <-- `a` is moved here. -/// let _ = dbg!(a); // <-- `a` is moved again; error! -/// ``` -/// -/// You can also use `dbg!()` without a value to just print the -/// file and line whenever it's reached. -/// -/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as -/// a tuple (and return it, too): -/// -/// ``` -/// assert_eq!(dbg!(1usize, 2u32), (1, 2)); -/// ``` -/// -/// However, a single argument with a trailing comma will still not be treated -/// as a tuple, following the convention of ignoring trailing commas in macro -/// invocations. You can use a 1-tuple directly if you need one: -/// -/// ``` -/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored -/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple -/// ``` -/// -/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr) -/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html -/// [`log`]: https://crates.io/crates/log -#[macro_export] -#[allow_internal_unstable(std_internals)] -#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")] -#[stable(feature = "dbg_macro", since = "1.32.0")] -macro_rules! dbg { - () => { - $crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!()) - }; - ($($val:expr),+ $(,)?) => { - $crate::macros::dbg_internal!(() () ($($val),+)) - }; -} - -/// Internal macro that processes a list of expressions and produces a chain of -/// nested `match`es, one for each expression, before finally calling `eprint!` -/// with the collected information and returning all the evaluated expressions -/// in a tuple. -/// -/// E.g. `dbg_internal!(() () (1, 2))` expands into -/// ```rust, ignore -/// match 1 { -/// tmp_1 => match 2 { -/// tmp_2 => { -/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */); -/// (tmp_1, tmp_2) -/// } -/// } -/// } -/// ``` -/// -/// This is necessary so that `dbg!` outputs don't get torn, see #136703. -#[doc(hidden)] -#[rustc_macro_transparency = "semiopaque"] -pub macro dbg_internal { - (($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{ - $crate::eprint!( - $crate::concat!($($piece),+), - $( - $crate::stringify!($processed), - // The `&T: Debug` check happens here (not in the format literal desugaring) - // to avoid format literal related messages and suggestions. - &&$bound as &dyn $crate::fmt::Debug - ),+, - // The location returned here is that of the macro invocation, so - // it will be the same for all expressions. Thus, label these - // arguments so that they can be reused in every piece of the - // formatting template. - file=$crate::file!(), - line=$crate::line!(), - column=$crate::column!() - ); - // Comma separate the variables only when necessary so that this will - // not yield a tuple for a single expression, but rather just parenthesize - // the expression. - ($($bound),+) - }}, - (($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => { - // Use of `match` here is intentional because it affects the lifetimes - // of temporaries - https://stackoverflow.com/a/48732525/1063961 - match $val { - tmp => $crate::macros::dbg_internal!( - ($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n") - ($($processed => $bound,)* $val => tmp) - ($($rest),*) - ), - } - }, -} diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs new file mode 120000 index 0000000..ac271d1 --- /dev/null +++ b/library/std/src/macros.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs \ No newline at end of file diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs deleted file mode 100644 index 7637440..0000000 --- a/library/std/src/os/mod.rs +++ /dev/null @@ -1,198 +0,0 @@ -//! OS-specific functionality. - -#![stable(feature = "os", since = "1.0.0")] -#![allow(missing_docs, nonstandard_style, missing_debug_implementations)] -#![allow(unsafe_op_in_unsafe_fn)] - -pub mod raw; - -// The code below could be written clearer using `cfg_if!`. However, the items below are -// publicly exported by `std` and external tools can have trouble analysing them because of the use -// of a macro that is not vendored by Rust and included in the toolchain. -// See https://github.com/rust-analyzer/rust-analyzer/issues/6038. - -// On certain platforms right now the "main modules" modules that are -// documented don't compile (missing things in `libc` which is empty), -// so just omit them with an empty module and add the "unstable" attribute. - -// darwin, unix, linux, wasi and windows are handled a bit differently. -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod darwin {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod unix {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod linux {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod wasi {} -#[cfg(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -))] -#[unstable(issue = "none", feature = "std_internals")] -pub mod windows {} - -// darwin -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(target_vendor = "apple", doc))] -pub mod darwin; - -// unix -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(all(not(target_os = "hermit"), any(unix, doc)))] -pub mod unix; - -// linux -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(target_os = "linux", doc))] -pub mod linux; - -// wasi -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(target_os = "wasi", any(target_env = "p1", target_env = "p2"), doc))] -pub mod wasi; - -#[cfg(any(all(target_os = "wasi", target_env = "p2"), doc))] -pub mod wasip2; - -// windows -#[cfg(not(all( - doc, - any( - all(target_arch = "wasm32", not(target_os = "wasi")), - all(target_vendor = "fortanix", target_env = "sgx") - ) -)))] -#[cfg(any(windows, doc))] -pub mod windows; - -// Others. -#[cfg(target_os = "aix")] -pub mod aix; -#[cfg(target_os = "android")] -pub mod android; -#[cfg(target_os = "cygwin")] -pub mod cygwin; -#[cfg(target_os = "dragonfly")] -pub mod dragonfly; -#[cfg(target_os = "emscripten")] -pub mod emscripten; -#[cfg(target_os = "espidf")] -pub mod espidf; -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -pub mod fortanix_sgx; -#[cfg(target_os = "freebsd")] -pub mod freebsd; -#[cfg(target_os = "fuchsia")] -pub mod fuchsia; -#[cfg(target_os = "haiku")] -pub mod haiku; -#[cfg(target_os = "hermit")] -pub mod hermit; -#[cfg(target_os = "horizon")] -pub mod horizon; -#[cfg(target_os = "hurd")] -pub mod hurd; -#[cfg(target_os = "illumos")] -pub mod illumos; -#[cfg(target_os = "ios")] -pub mod ios; -#[cfg(target_os = "l4re")] -pub mod l4re; -#[cfg(target_os = "macos")] -pub mod macos; -#[cfg(target_os = "motor")] -pub mod motor; -#[cfg(target_os = "netbsd")] -pub mod netbsd; -#[cfg(target_os = "nto")] -pub mod nto; -#[cfg(target_os = "nuttx")] -pub mod nuttx; -#[cfg(target_os = "openbsd")] -pub mod openbsd; -#[cfg(target_os = "redox")] -pub mod redox; -#[cfg(target_os = "rtems")] -pub mod rtems; -#[cfg(target_os = "solaris")] -pub mod solaris; -#[cfg(target_os = "solid_asp3")] -pub mod solid; -#[cfg(target_os = "trusty")] -pub mod trusty; -#[cfg(target_os = "uefi")] -pub mod uefi; -#[cfg(target_os = "vita")] -pub mod vita; -#[cfg(target_os = "vxworks")] -pub mod vxworks; -#[cfg(target_os = "xous")] -pub mod xous; - -#[cfg(any( - unix, - target_os = "hermit", - target_os = "trusty", - target_os = "wasi", - target_os = "motor", - doc -))] -pub mod fd; - -#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))] -mod net; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs new file mode 120000 index 0000000..0e98e62 --- /dev/null +++ b/library/std/src/os/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/os/mod.rs \ No newline at end of file diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs deleted file mode 100644 index 5b302e3..0000000 --- a/library/std/src/os/raw/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Compatibility module for C platform-specific types. Use [`core::ffi`] instead. - -#![stable(feature = "raw_os", since = "1.1.0")] - -#[cfg(test)] -mod tests; - -macro_rules! alias_core_ffi { - ($($t:ident)*) => {$( - #[stable(feature = "raw_os", since = "1.1.0")] - #[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))] - #[doc(cfg(all()))] - pub type $t = core::ffi::$t; - )*} -} - -alias_core_ffi! { - c_char c_schar c_uchar - c_short c_ushort - c_int c_uint - c_long c_ulong - c_longlong c_ulonglong - c_float - c_double - c_void -} diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs new file mode 120000 index 0000000..d608988 --- /dev/null +++ b/library/std/src/os/raw/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/os/raw/mod.rs \ No newline at end of file diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs deleted file mode 100644 index f41a22e..0000000 --- a/library/std/src/os/raw/tests.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![cfg(not(all(windows, target_env = "msvc")))] - -use crate::any::TypeId; - -macro_rules! ok { - ($($t:ident)*) => {$( - assert!(TypeId::of::() == TypeId::of::(), - "{} is wrong", stringify!($t)); - )*} -} - -#[test] -fn same() { - use crate::os::raw; - ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong - c_longlong c_ulonglong c_float c_double); -} diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs new file mode 120000 index 0000000..732670d --- /dev/null +++ b/library/std/src/os/raw/tests.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/os/raw/tests.rs \ No newline at end of file diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs deleted file mode 100644 index 658026a..0000000 --- a/library/std/src/panic.rs +++ /dev/null @@ -1,534 +0,0 @@ -//! Panic support in the standard library. - -#![stable(feature = "std_panic", since = "1.9.0")] - -use crate::any::Any; -use crate::sync::atomic::{Atomic, AtomicU8, Ordering}; -use crate::sync::{Condvar, Mutex, RwLock}; -use crate::thread::Result; -use crate::{collections, fmt, panicking}; - -#[stable(feature = "panic_hooks", since = "1.10.0")] -#[deprecated( - since = "1.82.0", - note = "use `PanicHookInfo` instead", - suggestion = "std::panic::PanicHookInfo" -)] -/// A struct providing information about a panic. -/// -/// `PanicInfo` has been renamed to [`PanicHookInfo`] to avoid confusion with -/// [`core::panic::PanicInfo`]. -pub type PanicInfo<'a> = PanicHookInfo<'a>; - -/// A struct providing information about a panic. -/// -/// `PanicHookInfo` structure is passed to a panic hook set by the [`set_hook`] function. -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occurred: {panic_info}"); -/// })); -/// -/// panic!("critical system failure"); -/// ``` -/// -/// [`set_hook`]: ../../std/panic/fn.set_hook.html -#[stable(feature = "panic_hook_info", since = "1.81.0")] -#[derive(Debug)] -pub struct PanicHookInfo<'a> { - payload: &'a (dyn Any + Send), - location: &'a Location<'a>, - can_unwind: bool, - force_no_backtrace: bool, -} - -impl<'a> PanicHookInfo<'a> { - #[inline] - pub(crate) fn new( - location: &'a Location<'a>, - payload: &'a (dyn Any + Send), - can_unwind: bool, - force_no_backtrace: bool, - ) -> Self { - PanicHookInfo { payload, location, can_unwind, force_no_backtrace } - } - - /// Returns the payload associated with the panic. - /// - /// This will commonly, but not always, be a `&'static str` or [`String`]. - /// If you only care about such payloads, use [`payload_as_str`] instead. - /// - /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a - /// panic payload of type `&'static str` or `String`. - /// - /// Only an invocation of [`panic_any`] - /// (or, in Rust 2018 and earlier, `panic!(x)` where `x` is something other than a string) - /// can result in a panic payload other than a `&'static str` or `String`. - /// - /// [`String`]: ../../std/string/struct.String.html - /// [`payload_as_str`]: PanicHookInfo::payload_as_str - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { - /// println!("panic occurred: {s:?}"); - /// } else if let Some(s) = panic_info.payload().downcast_ref::() { - /// println!("panic occurred: {s:?}"); - /// } else { - /// println!("panic occurred"); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[must_use] - #[inline] - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(dyn Any + Send) { - self.payload - } - - /// Returns the payload associated with the panic, if it is a string. - /// - /// This returns the payload if it is of type `&'static str` or `String`. - /// - /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a - /// panic payload where `payload_as_str` returns `Some`. - /// - /// Only an invocation of [`panic_any`] - /// (or, in Rust 2018 and earlier, `panic!(x)` where `x` is something other than a string) - /// can result in a panic payload where `payload_as_str` returns `None`. - /// - /// # Example - /// - /// ```should_panic - /// std::panic::set_hook(Box::new(|panic_info| { - /// if let Some(s) = panic_info.payload_as_str() { - /// println!("panic occurred: {s:?}"); - /// } else { - /// println!("panic occurred"); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[must_use] - #[inline] - #[stable(feature = "panic_payload_as_str", since = "1.91.0")] - pub fn payload_as_str(&self) -> Option<&str> { - if let Some(s) = self.payload.downcast_ref::<&str>() { - Some(s) - } else if let Some(s) = self.payload.downcast_ref::() { - Some(s) - } else { - None - } - } - - /// Returns information about the location from which the panic originated, - /// if available. - /// - /// This method will currently always return [`Some`], but this may change - /// in future versions. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}' at line {}", - /// location.file(), - /// location.line(), - /// ); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[must_use] - #[inline] - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn location(&self) -> Option<&Location<'_>> { - // NOTE: If this is changed to sometimes return None, - // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt. - Some(&self.location) - } - - /// Returns whether the panic handler is allowed to unwind the stack from - /// the point where the panic occurred. - /// - /// This is true for most kinds of panics with the exception of panics - /// caused by trying to unwind out of a `Drop` implementation or a function - /// whose ABI does not support unwinding. - /// - /// It is safe for a panic handler to unwind even when this function returns - /// false, however this will simply cause the panic handler to be called - /// again. - #[must_use] - #[inline] - #[unstable(feature = "panic_can_unwind", issue = "92988")] - pub fn can_unwind(&self) -> bool { - self.can_unwind - } - - #[unstable( - feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` and related macros", - issue = "none" - )] - #[doc(hidden)] - #[inline] - pub fn force_no_backtrace(&self) -> bool { - self.force_no_backtrace - } -} - -#[stable(feature = "panic_hook_display", since = "1.26.0")] -impl fmt::Display for PanicHookInfo<'_> { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("panicked at ")?; - self.location.fmt(formatter)?; - if let Some(payload) = self.payload_as_str() { - formatter.write_str(":\n")?; - formatter.write_str(payload)?; - } - Ok(()) - } -} - -#[doc(hidden)] -#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)] -#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] -#[rustc_macro_transparency = "semiopaque"] -pub macro panic_2015 { - () => ({ - $crate::rt::begin_panic("explicit panic") - }), - ($msg:expr $(,)?) => ({ - $crate::rt::begin_panic($msg); - }), - // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ({ - $crate::rt::panic_display(&$arg); - }), - ($fmt:expr, $($arg:tt)+) => ({ - // Semicolon to prevent temporaries inside the formatting machinery from - // being considered alive in the caller after the panic_fmt call. - $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+)); - }), -} - -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub use core::panic::Location; -#[doc(hidden)] -#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -pub use core::panic::panic_2021; -#[stable(feature = "catch_unwind", since = "1.9.0")] -pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; - -#[unstable(feature = "panic_update_hook", issue = "92649")] -pub use crate::panicking::update_hook; -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub use crate::panicking::{set_hook, take_hook}; - -/// Panics the current thread with the given message as the panic payload. -/// -/// The message can be of any (`Any + Send`) type, not just strings. -/// -/// The message is wrapped in a `Box<'static + Any + Send>`, which can be -/// accessed later using [`PanicHookInfo::payload`]. -/// -/// See the [`panic!`] macro for more information about panicking. -#[stable(feature = "panic_any", since = "1.51.0")] -#[inline] -#[track_caller] -#[cfg_attr(not(test), rustc_diagnostic_item = "panic_any")] -pub fn panic_any(msg: M) -> ! { - crate::panicking::begin_panic(msg); -} - -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Mutex {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for RwLock {} -#[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for Condvar {} - -#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] -impl RefUnwindSafe for Mutex {} -#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] -impl RefUnwindSafe for RwLock {} -#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] -impl RefUnwindSafe for Condvar {} - -// https://github.com/rust-lang/rust/issues/62301 -#[stable(feature = "hashbrown", since = "1.36.0")] -impl UnwindSafe for collections::HashMap -where - K: UnwindSafe, - V: UnwindSafe, - S: UnwindSafe, -{ -} - -#[unstable(feature = "abort_unwind", issue = "130338")] -pub use core::panic::abort_unwind; - -/// Invokes a closure, capturing the cause of an unwinding panic if one occurs. -/// -/// This function will return `Ok` with the closure's result if the closure does -/// not panic, and will return `Err(cause)` if the closure panics. The `cause` -/// returned is the object with which panic was originally invoked. -/// -/// Rust functions that are expected to be called from foreign code that does -/// not support unwinding (such as C compiled with `-fno-exceptions`) should be -/// defined using `extern "C"`, which ensures that if the Rust code panics, it -/// is automatically caught and the process is aborted. If this is the desired -/// behavior, it is not necessary to use `catch_unwind` explicitly. This -/// function should instead be used when more graceful error-handling is needed. -/// -/// It is **not** recommended to use this function for a general try/catch -/// mechanism. The [`Result`] type is more appropriate to use for functions that -/// can fail on a regular basis. Additionally, this function is not guaranteed -/// to catch all panics, see the "Notes" section below. -/// -/// The closure provided is required to adhere to the [`UnwindSafe`] trait to -/// ensure that all captured variables are safe to cross this boundary. The -/// purpose of this bound is to encode the concept of [exception safety][rfc] in -/// the type system. Most usage of this function should not need to worry about -/// this bound as programs are naturally unwind safe without `unsafe` code. If -/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to -/// quickly assert that the usage here is indeed unwind safe. -/// -/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md -/// -/// # Notes -/// -/// This function **might not catch all Rust panics**. A Rust panic is not -/// always implemented via unwinding, but can be implemented by aborting the -/// process as well. This function *only* catches unwinding panics, not those -/// that abort the process. -/// -/// If a custom panic hook has been set, it will be invoked before the panic is -/// caught, before unwinding. -/// -/// Although unwinding into Rust code with a foreign exception (e.g. an -/// exception thrown from C++ code, or a `panic!` in Rust code compiled or -/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`) -/// is permitted, catching such an exception using this function will have one -/// of two behaviors, and it is unspecified which will occur: -/// -/// * The process aborts, after executing all destructors of `f` and the -/// functions it called. -/// * The function returns a `Result::Err` containing an opaque type. -/// -/// Finally, be **careful in how you drop the result of this function**. If it -/// is `Err`, it contains the panic payload, and dropping that may in turn -/// panic! -/// -/// # Examples -/// -/// ``` -/// use std::panic; -/// -/// let result = panic::catch_unwind(|| { -/// println!("hello!"); -/// }); -/// assert!(result.is_ok()); -/// -/// let result = panic::catch_unwind(|| { -/// panic!("oh no!"); -/// }); -/// assert!(result.is_err()); -/// ``` -#[stable(feature = "catch_unwind", since = "1.9.0")] -pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { - unsafe { panicking::catch_unwind(f) } -} - -/// Triggers a panic without invoking the panic hook. -/// -/// This is designed to be used in conjunction with [`catch_unwind`] to, for -/// example, carry a panic across a layer of C code. -/// -/// # Notes -/// -/// Note that panics in Rust are not always implemented via unwinding, but they -/// may be implemented by aborting the process. If this function is called when -/// panics are implemented this way then this function will abort the process, -/// not trigger an unwind. -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// let result = panic::catch_unwind(|| { -/// if 1 != 2 { -/// panic!("oh no!"); -/// } -/// }); -/// -/// if let Err(err) = result { -/// panic::resume_unwind(err); -/// } -/// ``` -#[stable(feature = "resume_unwind", since = "1.9.0")] -pub fn resume_unwind(payload: Box) -> ! { - panicking::resume_unwind(payload) -} - -/// Makes all future panics abort directly without running the panic hook or unwinding. -/// -/// There is no way to undo this; the effect lasts until the process exits or -/// execs (or the equivalent). -/// -/// # Use after fork -/// -/// This function is particularly useful for calling after `libc::fork`. After `fork`, in a -/// multithreaded program it is (on many platforms) not safe to call the allocator. It is also -/// generally highly undesirable for an unwind to unwind past the `fork`, because that results in -/// the unwind propagating to code that was only ever expecting to run in the parent. -/// -/// `panic::always_abort()` helps avoid both of these. It directly avoids any further unwinding, -/// and if there is a panic, the abort will occur without allocating provided that the arguments to -/// panic can be formatted without allocating. -/// -/// Examples -/// -/// ```no_run -/// #![feature(panic_always_abort)] -/// use std::panic; -/// -/// panic::always_abort(); -/// -/// let _ = panic::catch_unwind(|| { -/// panic!("inside the catch"); -/// }); -/// -/// // We will have aborted already, due to the panic. -/// unreachable!(); -/// ``` -#[unstable(feature = "panic_always_abort", issue = "84438")] -pub fn always_abort() { - crate::panicking::panic_count::set_always_abort(); -} - -/// The configuration for whether and how the default panic hook will capture -/// and display the backtrace. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[unstable(feature = "panic_backtrace_config", issue = "93346")] -#[non_exhaustive] -pub enum BacktraceStyle { - /// Prints a terser backtrace which ideally only contains relevant - /// information. - Short, - /// Prints a backtrace with all possible information. - Full, - /// Disable collecting and displaying backtraces. - Off, -} - -impl BacktraceStyle { - pub(crate) fn full() -> Option { - if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None } - } - - fn as_u8(self) -> u8 { - match self { - BacktraceStyle::Short => 1, - BacktraceStyle::Full => 2, - BacktraceStyle::Off => 3, - } - } - - fn from_u8(s: u8) -> Option { - match s { - 1 => Some(BacktraceStyle::Short), - 2 => Some(BacktraceStyle::Full), - 3 => Some(BacktraceStyle::Off), - _ => None, - } - } -} - -// Tracks whether we should/can capture a backtrace, and how we should display -// that backtrace. -// -// Internally stores equivalent of an Option. -static SHOULD_CAPTURE: Atomic = AtomicU8::new(0); - -/// Configures whether the default panic hook will capture and display a -/// backtrace. -/// -/// The default value for this setting may be set by the `RUST_BACKTRACE` -/// environment variable; see the details in [`get_backtrace_style`]. -#[unstable(feature = "panic_backtrace_config", issue = "93346")] -pub fn set_backtrace_style(style: BacktraceStyle) { - if cfg!(feature = "backtrace") { - // If the `backtrace` feature of this crate is enabled, set the backtrace style. - SHOULD_CAPTURE.store(style.as_u8(), Ordering::Relaxed); - } -} - -/// Checks whether the standard library's panic hook will capture and print a -/// backtrace. -/// -/// This function will, if a backtrace style has not been set via -/// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to -/// determine a default value for the backtrace formatting: -/// -/// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE` -/// environment variable if `set_backtrace_style` has not been called to -/// override the default value. After a call to `set_backtrace_style` or -/// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect. -/// -/// `RUST_BACKTRACE` is read according to these rules: -/// -/// * `0` for `BacktraceStyle::Off` -/// * `full` for `BacktraceStyle::Full` -/// * `1` for `BacktraceStyle::Short` -/// * Other values are currently `BacktraceStyle::Short`, but this may change in -/// the future -/// -/// Returns `None` if backtraces aren't currently supported. -#[unstable(feature = "panic_backtrace_config", issue = "93346")] -pub fn get_backtrace_style() -> Option { - if !cfg!(feature = "backtrace") { - // If the `backtrace` feature of this crate isn't enabled quickly return - // `Unsupported` so this can be constant propagated all over the place - // to optimize away callers. - return None; - } - - let current = SHOULD_CAPTURE.load(Ordering::Relaxed); - if let Some(style) = BacktraceStyle::from_u8(current) { - return Some(style); - } - - let format = match crate::env::var_os("RUST_BACKTRACE") { - Some(x) if &x == "0" => BacktraceStyle::Off, - Some(x) if &x == "full" => BacktraceStyle::Full, - Some(_) => BacktraceStyle::Short, - None if crate::sys::backtrace::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full, - None => BacktraceStyle::Off, - }; - - match SHOULD_CAPTURE.compare_exchange(0, format.as_u8(), Ordering::Relaxed, Ordering::Relaxed) { - Ok(_) => Some(format), - Err(new) => BacktraceStyle::from_u8(new), - } -} diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs new file mode 120000 index 0000000..57f5a73 --- /dev/null +++ b/library/std/src/panic.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs \ No newline at end of file diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs deleted file mode 100644 index a4a974d..0000000 --- a/library/std/src/panicking.rs +++ /dev/null @@ -1,894 +0,0 @@ -//! Implementation of various bits and pieces of the `panic!` macro and -//! associated runtime pieces. -//! -//! Specifically, this module contains the implementation of: -//! -//! * Panic hooks -//! * Executing a panic up to doing the actual implementation -//! * Shims around "try" - -#![deny(unsafe_op_in_unsafe_fn)] - -use core::panic::{Location, PanicPayload}; - -// make sure to use the stderr output configured -// by libtest in the real copy of std -#[cfg(test)] -use realstd::io::try_set_output_capture; - -use crate::any::Any; -#[cfg(not(test))] -use crate::io::try_set_output_capture; -use crate::mem::{self, ManuallyDrop}; -use crate::panic::{BacktraceStyle, PanicHookInfo}; -use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; -use crate::sync::nonpoison::RwLock; -use crate::sys::backtrace; -use crate::sys::stdio::panic_output; -use crate::{fmt, intrinsics, process, thread}; - -// This forces codegen of the function called by panic!() inside the std crate, rather than in -// downstream crates. Primarily this is useful for rustc's codegen tests, which rely on noticing -// complete removal of panic from generated IR. Since begin_panic is inline(never), it's only -// codegen'd once per crate-graph so this pushes that to std rather than our codegen test crates. -// -// (See https://github.com/rust-lang/rust/pull/123244 for more info on why). -// -// If this is causing problems we can also modify those codegen tests to use a crate type like -// cdylib which doesn't export "Rust" symbols to downstream linkage units. -#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] -#[doc(hidden)] -#[allow(dead_code)] -#[used(compiler)] -pub static EMPTY_PANIC: fn(&'static str) -> ! = - begin_panic::<&'static str> as fn(&'static str) -> !; - -// Binary interface to the panic runtime that the standard library depends on. -// -// The standard library is tagged with `#![needs_panic_runtime]` (introduced in -// RFC 1513) to indicate that it requires some other crate tagged with -// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to -// implement these symbols (with the same signatures) so we can get matched up -// to them. -// -// One day this may look a little less ad-hoc with the compiler helping out to -// hook up these functions, but it is not this day! -#[allow(improper_ctypes)] -unsafe extern "C" { - #[rustc_std_internal_symbol] - fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); -} - -unsafe extern "Rust" { - /// `PanicPayload` lazily performs allocation only when needed (this avoids - /// allocations when using the "abort" panic runtime). - #[rustc_std_internal_symbol] - fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32; -} - -/// This function is called by the panic runtime if FFI code catches a Rust -/// panic but doesn't rethrow it. We don't support this case since it messes -/// with our panic count. -#[cfg(not(test))] -#[rustc_std_internal_symbol] -extern "C" fn __rust_drop_panic() -> ! { - rtabort!("Rust panics must be rethrown"); -} - -/// This function is called by the panic runtime if it catches an exception -/// object which does not correspond to a Rust panic. -#[cfg(not(test))] -#[rustc_std_internal_symbol] -extern "C" fn __rust_foreign_exception() -> ! { - rtabort!("Rust cannot catch foreign exceptions"); -} - -#[derive(Default)] -enum Hook { - #[default] - Default, - Custom(Box) + 'static + Sync + Send>), -} - -impl Hook { - #[inline] - fn into_box(self) -> Box) + 'static + Sync + Send> { - match self { - Hook::Default => Box::new(default_hook), - Hook::Custom(hook) => hook, - } - } -} - -static HOOK: RwLock = RwLock::new(Hook::Default); - -/// Registers a custom panic hook, replacing the previously registered hook. -/// -/// The panic hook is invoked when a thread panics, but before the panic runtime -/// is invoked. As such, the hook will run with both the aborting and unwinding -/// runtimes. -/// -/// The default hook, which is registered at startup, prints a message to standard error and -/// generates a backtrace if requested. This behavior can be customized using the `set_hook` function. -/// The current hook can be retrieved while reinstating the default hook with the [`take_hook`] -/// function. -/// -/// [`take_hook`]: ./fn.take_hook.html -/// -/// The hook is provided with a `PanicHookInfo` struct which contains information -/// about the origin of the panic, including the payload passed to `panic!` and -/// the source code location from which the panic originated. -/// -/// The panic hook is a global resource. -/// -/// # Panics -/// -/// Panics if called from a panicking thread. -/// -/// # Examples -/// -/// The following will print "Custom panic hook": -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|_| { -/// println!("Custom panic hook"); -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn set_hook(hook: Box) + 'static + Sync + Send>) { - if thread::panicking() { - panic!("cannot modify the panic hook from a panicking thread"); - } - - // Drop the old hook after changing the hook to avoid deadlocking if its - // destructor panics. - drop(HOOK.replace(Hook::Custom(hook))); -} - -/// Unregisters the current panic hook and returns it, registering the default hook -/// in its place. -/// -/// *See also the function [`set_hook`].* -/// -/// [`set_hook`]: ./fn.set_hook.html -/// -/// If the default hook is registered it will be returned, but remain registered. -/// -/// # Panics -/// -/// Panics if called from a panicking thread. -/// -/// # Examples -/// -/// The following will print "Normal panic": -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|_| { -/// println!("Custom panic hook"); -/// })); -/// -/// let _ = panic::take_hook(); -/// -/// panic!("Normal panic"); -/// ``` -#[must_use] -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn take_hook() -> Box) + 'static + Sync + Send> { - if thread::panicking() { - panic!("cannot modify the panic hook from a panicking thread"); - } - - HOOK.replace(Hook::Default).into_box() -} - -/// Atomic combination of [`take_hook`] and [`set_hook`]. Use this to replace the panic handler with -/// a new panic handler that does something and then executes the old handler. -/// -/// [`take_hook`]: ./fn.take_hook.html -/// [`set_hook`]: ./fn.set_hook.html -/// -/// # Panics -/// -/// Panics if called from a panicking thread. -/// -/// # Examples -/// -/// The following will print the custom message, and then the normal output of panic. -/// -/// ```should_panic -/// #![feature(panic_update_hook)] -/// use std::panic; -/// -/// // Equivalent to -/// // let prev = panic::take_hook(); -/// // panic::set_hook(Box::new(move |info| { -/// // println!("..."); -/// // prev(info); -/// // })); -/// panic::update_hook(move |prev, info| { -/// println!("Print custom message and execute panic handler as usual"); -/// prev(info); -/// }); -/// -/// panic!("Custom and then normal"); -/// ``` -#[unstable(feature = "panic_update_hook", issue = "92649")] -pub fn update_hook(hook_fn: F) -where - F: Fn(&(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), &PanicHookInfo<'_>) - + Sync - + Send - + 'static, -{ - if thread::panicking() { - panic!("cannot modify the panic hook from a panicking thread"); - } - - let mut hook = HOOK.write(); - let prev = mem::take(&mut *hook).into_box(); - *hook = Hook::Custom(Box::new(move |info| hook_fn(&prev, info))); -} - -/// The default panic handler. -#[optimize(size)] -fn default_hook(info: &PanicHookInfo<'_>) { - // If this is a double panic, make sure that we print a backtrace - // for this panic. Otherwise only print it if logging is enabled. - let backtrace = if info.force_no_backtrace() { - None - } else if panic_count::get_count() >= 2 { - BacktraceStyle::full() - } else { - crate::panic::get_backtrace_style() - }; - - // The current implementation always returns `Some`. - let location = info.location().unwrap(); - - let msg = payload_as_str(info.payload()); - - let write = #[optimize(size)] - |err: &mut dyn crate::io::Write| { - // Use a lock to prevent mixed output in multithreading context. - // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. - let mut lock = backtrace::lock(); - - thread::with_current_name(|name| { - let name = name.unwrap_or(""); - let tid = thread::current_os_id(); - - // Try to write the panic message to a buffer first to prevent other concurrent outputs - // interleaving with it. - let mut buffer = [0u8; 512]; - let mut cursor = crate::io::Cursor::new(&mut buffer[..]); - - let write_msg = |dst: &mut dyn crate::io::Write| { - // We add a newline to ensure the panic message appears at the start of a line. - writeln!(dst, "\nthread '{name}' ({tid}) panicked at {location}:\n{msg}") - }; - - if write_msg(&mut cursor).is_ok() { - let pos = cursor.position() as usize; - let _ = err.write_all(&buffer[0..pos]); - } else { - // The message did not fit into the buffer, write it directly instead. - let _ = write_msg(err); - }; - }); - - static FIRST_PANIC: Atomic = AtomicBool::new(true); - - match backtrace { - Some(BacktraceStyle::Short) => { - drop(lock.print(err, crate::backtrace_rs::PrintFmt::Short)) - } - Some(BacktraceStyle::Full) => { - drop(lock.print(err, crate::backtrace_rs::PrintFmt::Full)) - } - Some(BacktraceStyle::Off) => { - if FIRST_PANIC.swap(false, Ordering::Relaxed) { - let _ = writeln!( - err, - "note: run with `RUST_BACKTRACE=1` environment variable to display a \ - backtrace" - ); - if cfg!(miri) { - let _ = writeln!( - err, - "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \ - for the environment variable to have an effect" - ); - } - } - } - // If backtraces aren't supported or are forced-off, do nothing. - None => {} - } - }; - - if let Ok(Some(local)) = try_set_output_capture(None) { - write(&mut *local.lock().unwrap_or_else(|e| e.into_inner())); - try_set_output_capture(Some(local)).ok(); - } else if let Some(mut out) = panic_output() { - write(&mut out); - } -} - -#[cfg(not(test))] -#[doc(hidden)] -#[cfg(panic = "immediate-abort")] -#[unstable(feature = "update_panic_count", issue = "none")] -pub mod panic_count { - /// A reason for forcing an immediate abort on panic. - #[derive(Debug)] - pub enum MustAbort { - AlwaysAbort, - PanicInHook, - } - - #[inline] - pub fn increase(run_panic_hook: bool) -> Option { - None - } - - #[inline] - pub fn finished_panic_hook() {} - - #[inline] - pub fn decrease() {} - - #[inline] - pub fn set_always_abort() {} - - // Disregards ALWAYS_ABORT_FLAG - #[inline] - #[must_use] - pub fn get_count() -> usize { - 0 - } - - #[must_use] - #[inline] - pub fn count_is_zero() -> bool { - true - } -} - -#[cfg(not(test))] -#[doc(hidden)] -#[cfg(not(panic = "immediate-abort"))] -#[unstable(feature = "update_panic_count", issue = "none")] -pub mod panic_count { - use crate::cell::Cell; - use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; - - const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1); - - /// A reason for forcing an immediate abort on panic. - #[derive(Debug)] - pub enum MustAbort { - AlwaysAbort, - PanicInHook, - } - - // Panic count for the current thread and whether a panic hook is currently - // being executed.. - thread_local! { - static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) } - } - - // Sum of panic counts from all threads. The purpose of this is to have - // a fast path in `count_is_zero` (which is used by `panicking`). In any particular - // thread, if that thread currently views `GLOBAL_PANIC_COUNT` as being zero, - // then `LOCAL_PANIC_COUNT` in that thread is zero. This invariant holds before - // and after increase and decrease, but not necessarily during their execution. - // - // Additionally, the top bit of GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG) - // records whether panic::always_abort() has been called. This can only be - // set, never cleared. - // panic::always_abort() is usually called to prevent memory allocations done by - // the panic handling in the child created by `libc::fork`. - // Memory allocations performed in a child created with `libc::fork` are undefined - // behavior in most operating systems. - // Accessing LOCAL_PANIC_COUNT in a child created by `libc::fork` would lead to a memory - // allocation. Only GLOBAL_PANIC_COUNT can be accessed in this situation. This is - // sufficient because a child process will always have exactly one thread only. - // See also #85261 for details. - // - // This could be viewed as a struct containing a single bit and an n-1-bit - // value, but if we wrote it like that it would be more than a single word, - // and even a newtype around usize would be clumsy because we need atomics. - // But we use such a tuple for the return type of increase(). - // - // Stealing a bit is fine because it just amounts to assuming that each - // panicking thread consumes at least 2 bytes of address space. - static GLOBAL_PANIC_COUNT: Atomic = AtomicUsize::new(0); - - // Increases the global and local panic count, and returns whether an - // immediate abort is required. - // - // This also updates thread-local state to keep track of whether a panic - // hook is currently executing. - pub fn increase(run_panic_hook: bool) -> Option { - let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed); - if global_count & ALWAYS_ABORT_FLAG != 0 { - // Do *not* access thread-local state, we might be after a `fork`. - return Some(MustAbort::AlwaysAbort); - } - - LOCAL_PANIC_COUNT.with(|c| { - let (count, in_panic_hook) = c.get(); - if in_panic_hook { - return Some(MustAbort::PanicInHook); - } - c.set((count + 1, run_panic_hook)); - None - }) - } - - pub fn finished_panic_hook() { - LOCAL_PANIC_COUNT.with(|c| { - let (count, _) = c.get(); - c.set((count, false)); - }); - } - - pub fn decrease() { - GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); - LOCAL_PANIC_COUNT.with(|c| { - let (count, _) = c.get(); - c.set((count - 1, false)); - }); - } - - pub fn set_always_abort() { - GLOBAL_PANIC_COUNT.fetch_or(ALWAYS_ABORT_FLAG, Ordering::Relaxed); - } - - // Disregards ALWAYS_ABORT_FLAG - #[must_use] - pub fn get_count() -> usize { - LOCAL_PANIC_COUNT.with(|c| c.get().0) - } - - // Disregards ALWAYS_ABORT_FLAG - #[must_use] - #[inline] - pub fn count_is_zero() -> bool { - if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 { - // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads - // (including the current one) will have `LOCAL_PANIC_COUNT` - // equal to zero, so TLS access can be avoided. - // - // In terms of performance, a relaxed atomic load is similar to a normal - // aligned memory read (e.g., a mov instruction in x86), but with some - // compiler optimization restrictions. On the other hand, a TLS access - // might require calling a non-inlinable function (such as `__tls_get_addr` - // when using the GD TLS model). - true - } else { - is_zero_slow_path() - } - } - - // Slow path is in a separate function to reduce the amount of code - // inlined from `count_is_zero`. - #[inline(never)] - #[cold] - fn is_zero_slow_path() -> bool { - LOCAL_PANIC_COUNT.with(|c| c.get().0 == 0) - } -} - -#[cfg(test)] -pub use realstd::rt::panic_count; - -/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(panic = "immediate-abort")] -pub unsafe fn catch_unwind R>(f: F) -> Result> { - Ok(f()) -} - -/// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(not(panic = "immediate-abort"))] -pub unsafe fn catch_unwind R>(f: F) -> Result> { - union Data { - f: ManuallyDrop, - r: ManuallyDrop, - p: ManuallyDrop>, - } - - // We do some sketchy operations with ownership here for the sake of - // performance. We can only pass pointers down to `do_call` (can't pass - // objects by value), so we do all the ownership tracking here manually - // using a union. - // - // We go through a transition where: - // - // * First, we set the data field `f` to be the argumentless closure that we're going to call. - // * When we make the function call, the `do_call` function below, we take - // ownership of the function pointer. At this point the `data` union is - // entirely uninitialized. - // * If the closure successfully returns, we write the return value into the - // data's return slot (field `r`). - // * If the closure panics (`do_catch` below), we write the panic payload into field `p`. - // * Finally, when we come back out of the `try` intrinsic we're - // in one of two states: - // - // 1. The closure didn't panic, in which case the return value was - // filled in. We move it out of `data.r` and return it. - // 2. The closure panicked, in which case the panic payload was - // filled in. We move it out of `data.p` and return it. - // - // Once we stack all that together we should have the "most efficient' - // method of calling a catch panic whilst juggling ownership. - let mut data = Data { f: ManuallyDrop::new(f) }; - - let data_ptr = (&raw mut data) as *mut u8; - // SAFETY: - // - // Access to the union's fields: this is `std` and we know that the `catch_unwind` - // intrinsic fills in the `r` or `p` union field based on its return value. - // - // The call to `intrinsics::catch_unwind` is made safe by: - // - `do_call`, the first argument, can be called with the initial `data_ptr`. - // - `do_catch`, the second argument, can be called with the `data_ptr` as well. - // See their safety preconditions for more information - unsafe { - return if intrinsics::catch_unwind(do_call::, data_ptr, do_catch::) == 0 { - Ok(ManuallyDrop::into_inner(data.r)) - } else { - Err(ManuallyDrop::into_inner(data.p)) - }; - } - - // We consider unwinding to be rare, so mark this function as cold. However, - // do not mark it no-inline -- that decision is best to leave to the - // optimizer (in most cases this function is not inlined even as a normal, - // non-cold function, though, as of the writing of this comment). - #[cold] - #[optimize(size)] - unsafe fn cleanup(payload: *mut u8) -> Box { - // SAFETY: The whole unsafe block hinges on a correct implementation of - // the panic handler `__rust_panic_cleanup`. As such we can only - // assume it returns the correct thing for `Box::from_raw` to work - // without undefined behavior. - let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) }; - panic_count::decrease(); - obj - } - - // SAFETY: - // data must be non-NUL, correctly aligned, and a pointer to a `Data` - // Its must contains a valid `f` (type: F) value that can be use to fill - // `data.r`. - // - // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` - // expects normal function pointers. - #[inline] - fn do_call R, R>(data: *mut u8) { - // SAFETY: this is the responsibility of the caller, see above. - unsafe { - let data = data as *mut Data; - let data = &mut (*data); - let f = ManuallyDrop::take(&mut data.f); - data.r = ManuallyDrop::new(f()); - } - } - - // We *do* want this part of the catch to be inlined: this allows the - // compiler to properly track accesses to the Data union and optimize it - // away most of the time. - // - // SAFETY: - // data must be non-NUL, correctly aligned, and a pointer to a `Data` - // Since this uses `cleanup` it also hinges on a correct implementation of - // `__rustc_panic_cleanup`. - // - // This function cannot be marked as `unsafe` because `intrinsics::catch_unwind` - // expects normal function pointers. - #[inline] - #[rustc_nounwind] // `intrinsic::catch_unwind` requires catch fn to be nounwind - fn do_catch R, R>(data: *mut u8, payload: *mut u8) { - // SAFETY: this is the responsibility of the caller, see above. - // - // When `__rustc_panic_cleaner` is correctly implemented we can rely - // on `obj` being the correct thing to pass to `data.p` (after wrapping - // in `ManuallyDrop`). - unsafe { - let data = data as *mut Data; - let data = &mut (*data); - let obj = cleanup(payload); - data.p = ManuallyDrop::new(obj); - } - } -} - -/// Determines whether the current thread is unwinding because of panic. -#[inline] -pub fn panicking() -> bool { - !panic_count::count_is_zero() -} - -/// Entry point of panics from the core crate (`panic_impl` lang item). -#[cfg(not(any(test, doctest)))] -#[panic_handler] -pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { - struct FormatStringPayload<'a> { - inner: &'a core::panic::PanicMessage<'a>, - string: Option, - } - - impl FormatStringPayload<'_> { - fn fill(&mut self) -> &mut String { - let inner = self.inner; - // Lazily, the first time this gets called, run the actual string formatting. - self.string.get_or_insert_with(|| { - let mut s = String::new(); - let mut fmt = fmt::Formatter::new(&mut s, fmt::FormattingOptions::new()); - let _err = fmt::Display::fmt(&inner, &mut fmt); - s - }) - } - } - - unsafe impl PanicPayload for FormatStringPayload<'_> { - fn take_box(&mut self) -> *mut (dyn Any + Send) { - // We do two allocations here, unfortunately. But (a) they're required with the current - // scheme, and (b) we don't handle panic + OOM properly anyway (see comment in - // begin_panic below). - let contents = mem::take(self.fill()); - Box::into_raw(Box::new(contents)) - } - - fn get(&mut self) -> &(dyn Any + Send) { - self.fill() - } - } - - impl fmt::Display for FormatStringPayload<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(s) = &self.string { - f.write_str(s) - } else { - fmt::Display::fmt(&self.inner, f) - } - } - } - - struct StaticStrPayload(&'static str); - - unsafe impl PanicPayload for StaticStrPayload { - fn take_box(&mut self) -> *mut (dyn Any + Send) { - Box::into_raw(Box::new(self.0)) - } - - fn get(&mut self) -> &(dyn Any + Send) { - &self.0 - } - - fn as_str(&mut self) -> Option<&str> { - Some(self.0) - } - } - - impl fmt::Display for StaticStrPayload { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.0) - } - } - - let loc = info.location().unwrap(); // The current implementation always returns Some - let msg = info.message(); - crate::sys::backtrace::__rust_end_short_backtrace(move || { - if let Some(s) = msg.as_str() { - panic_with_hook( - &mut StaticStrPayload(s), - loc, - info.can_unwind(), - info.force_no_backtrace(), - ); - } else { - panic_with_hook( - &mut FormatStringPayload { inner: &msg, string: None }, - loc, - info.can_unwind(), - info.force_no_backtrace(), - ); - } - }) -} - -/// This is the entry point of panicking for the non-format-string variants of -/// panic!() and assert!(). In particular, this is the only entry point that supports -/// arbitrary payloads, not just format strings. -#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] -#[cfg_attr(not(any(test, doctest)), lang = "begin_panic")] -// lang item for CTFE panic support -// never inline unless panic=immediate-abort to avoid code -// bloat at the call sites as much as possible -#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] -#[cfg_attr(panic = "immediate-abort", inline)] -#[track_caller] -#[rustc_do_not_const_check] // hooked by const-eval -pub const fn begin_panic(msg: M) -> ! { - if cfg!(panic = "immediate-abort") { - intrinsics::abort() - } - - struct Payload { - inner: Option, - } - - unsafe impl PanicPayload for Payload { - fn take_box(&mut self) -> *mut (dyn Any + Send) { - // Note that this should be the only allocation performed in this code path. Currently - // this means that panic!() on OOM will invoke this code path, but then again we're not - // really ready for panic on OOM anyway. If we do start doing this, then we should - // propagate this allocation to be performed in the parent of this thread instead of the - // thread that's panicking. - let data = match self.inner.take() { - Some(a) => Box::new(a) as Box, - None => process::abort(), - }; - Box::into_raw(data) - } - - fn get(&mut self) -> &(dyn Any + Send) { - match self.inner { - Some(ref a) => a, - None => process::abort(), - } - } - } - - impl fmt::Display for Payload { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.inner { - Some(a) => f.write_str(payload_as_str(a)), - None => process::abort(), - } - } - } - - let loc = Location::caller(); - crate::sys::backtrace::__rust_end_short_backtrace(move || { - panic_with_hook( - &mut Payload { inner: Some(msg) }, - loc, - /* can_unwind */ true, - /* force_no_backtrace */ false, - ) - }) -} - -fn payload_as_str(payload: &dyn Any) -> &str { - if let Some(&s) = payload.downcast_ref::<&'static str>() { - s - } else if let Some(s) = payload.downcast_ref::() { - s.as_str() - } else { - "Box" - } -} - -/// Central point for dispatching panics. -/// -/// Executes the primary logic for a panic, including checking for recursive -/// panics, panic hooks, and finally dispatching to the panic runtime to either -/// abort or unwind. -#[optimize(size)] -fn panic_with_hook( - payload: &mut dyn PanicPayload, - location: &Location<'_>, - can_unwind: bool, - force_no_backtrace: bool, -) -> ! { - let must_abort = panic_count::increase(true); - - // Check if we need to abort immediately. - if let Some(must_abort) = must_abort { - match must_abort { - panic_count::MustAbort::PanicInHook => { - // Don't try to format the message in this case, perhaps that is causing the - // recursive panics. However if the message is just a string, no user-defined - // code is involved in printing it, so that is risk-free. - let message: &str = payload.as_str().unwrap_or_default(); - rtprintpanic!( - "panicked at {location}:\n{message}\nthread panicked while processing panic. aborting.\n" - ); - } - panic_count::MustAbort::AlwaysAbort => { - // Unfortunately, this does not print a backtrace, because creating - // a `Backtrace` will allocate, which we must avoid here. - rtprintpanic!("aborting due to panic at {location}:\n{payload}\n"); - } - } - crate::process::abort(); - } - - match *HOOK.read() { - // Some platforms (like wasm) know that printing to stderr won't ever actually - // print anything, and if that's the case we can skip the default - // hook. Since string formatting happens lazily when calling `payload` - // methods, this means we avoid formatting the string at all! - // (The panic runtime might still call `payload.take_box()` though and trigger - // formatting.) - Hook::Default if panic_output().is_none() => {} - Hook::Default => { - default_hook(&PanicHookInfo::new( - location, - payload.get(), - can_unwind, - force_no_backtrace, - )); - } - Hook::Custom(ref hook) => { - hook(&PanicHookInfo::new(location, payload.get(), can_unwind, force_no_backtrace)); - } - } - - // Indicate that we have finished executing the panic hook. After this point - // it is fine if there is a panic while executing destructors, as long as it - // it contained within a `catch_unwind`. - panic_count::finished_panic_hook(); - - if !can_unwind { - // If a thread panics while running destructors or tries to unwind - // through a nounwind function (e.g. extern "C") then we cannot continue - // unwinding and have to abort immediately. - rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); - crate::process::abort(); - } - - rust_panic(payload) -} - -/// This is the entry point for `resume_unwind`. -/// It just forwards the payload to the panic runtime. -#[cfg_attr(panic = "immediate-abort", inline)] -pub fn resume_unwind(payload: Box) -> ! { - panic_count::increase(false); - - struct RewrapBox(Box); - - unsafe impl PanicPayload for RewrapBox { - fn take_box(&mut self) -> *mut (dyn Any + Send) { - Box::into_raw(mem::replace(&mut self.0, Box::new(()))) - } - - fn get(&mut self) -> &(dyn Any + Send) { - &*self.0 - } - } - - impl fmt::Display for RewrapBox { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(payload_as_str(&self.0)) - } - } - - rust_panic(&mut RewrapBox(payload)) -} - -/// A function with a fixed suffix (through `rustc_std_internal_symbol`) -/// on which to slap yer breakpoints. -#[inline(never)] -#[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(not(panic = "immediate-abort"))] -fn rust_panic(msg: &mut dyn PanicPayload) -> ! { - let code = unsafe { __rust_start_panic(msg) }; - rtabort!("failed to initiate panic, error {code}") -} - -#[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(panic = "immediate-abort")] -fn rust_panic(_: &mut dyn PanicPayload) -> ! { - crate::intrinsics::abort(); -} diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs new file mode 120000 index 0000000..4653bf2 --- /dev/null +++ b/library/std/src/panicking.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs \ No newline at end of file diff --git a/library/std/src/pat.rs b/library/std/src/pat.rs deleted file mode 100644 index aeddd84..0000000 --- a/library/std/src/pat.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Helper module for exporting the `pattern_type` macro - -pub use core::pattern_type; diff --git a/library/std/src/pat.rs b/library/std/src/pat.rs new file mode 120000 index 0000000..f35ae81 --- /dev/null +++ b/library/std/src/pat.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/pat.rs \ No newline at end of file diff --git a/library/std/src/path.rs b/library/std/src/path.rs deleted file mode 100644 index 0b2b5f7..0000000 --- a/library/std/src/path.rs +++ /dev/null @@ -1,4086 +0,0 @@ -//! Cross-platform path manipulation. -//! -//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] -//! and [`str`]), for working with paths abstractly. These types are thin wrappers -//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly -//! on strings according to the local platform's path syntax. -//! -//! Paths can be parsed into [`Component`]s by iterating over the structure -//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly -//! correspond to the substrings between path separators (`/` or `\`). You can -//! reconstruct an equivalent path from components with the [`push`] method on -//! [`PathBuf`]; note that the paths may differ syntactically by the -//! normalization described in the documentation for the [`components`] method. -//! -//! ## Case sensitivity -//! -//! Unless otherwise indicated path methods that do not access the filesystem, -//! such as [`Path::starts_with`] and [`Path::ends_with`], are case sensitive no -//! matter the platform or filesystem. An exception to this is made for Windows -//! drive letters. -//! -//! ## Path normalization -//! -//! Several methods in this module perform basic path normalization by disregarding -//! repeated separators, non-leading `.` components, and trailing separators. These include: -//! - Methods for iteration, such as [`Path::components`] and [`Path::iter`] -//! - Methods for inspection, such as [`Path::has_root`] -//! - Comparisons using [`PartialEq`], [`PartialOrd`], and [`Ord`] -//! -//! [`Path::join`] and [`PathBuf::push`] also disregard trailing slashes. -//! -// FIXME(normalize_lexically): mention normalize_lexically once stable -//! These methods **do not** resolve `..` components or symlinks. For full normalization -//! including `..` resolution, use [`Path::canonicalize`] (which does access the filesystem). -//! -//! ## Simple usage -//! -//! Path manipulation includes both parsing components from slices and building -//! new owned paths. -//! -//! To parse a path, you can create a [`Path`] slice from a [`str`] -//! slice and start asking questions: -//! -//! ``` -//! use std::path::Path; -//! use std::ffi::OsStr; -//! -//! let path = Path::new("/tmp/foo/bar.txt"); -//! -//! let parent = path.parent(); -//! assert_eq!(parent, Some(Path::new("/tmp/foo"))); -//! -//! let file_stem = path.file_stem(); -//! assert_eq!(file_stem, Some(OsStr::new("bar"))); -//! -//! let extension = path.extension(); -//! assert_eq!(extension, Some(OsStr::new("txt"))); -//! ``` -//! -//! To build or modify paths, use [`PathBuf`]: -//! -//! ``` -//! use std::path::PathBuf; -//! -//! // This way works... -//! let mut path = PathBuf::from("c:\\"); -//! -//! path.push("windows"); -//! path.push("system32"); -//! -//! path.set_extension("dll"); -//! -//! // ... but push is best used if you don't know everything up -//! // front. If you do, this way is better: -//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect(); -//! ``` -//! -//! [`components`]: Path::components -//! [`push`]: PathBuf::push - -#![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] - -use core::clone::CloneToUninit; - -use crate::borrow::{Borrow, Cow}; -use crate::collections::TryReserveError; -use crate::error::Error; -use crate::ffi::{OsStr, OsString, os_str}; -use crate::hash::{Hash, Hasher}; -use crate::iter::FusedIterator; -use crate::ops::{self, Deref}; -use crate::rc::Rc; -use crate::str::FromStr; -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}; - -//////////////////////////////////////////////////////////////////////////////// -// GENERAL NOTES -//////////////////////////////////////////////////////////////////////////////// -// -// Parsing in this module is done by directly transmuting OsStr to [u8] slices, -// taking advantage of the fact that OsStr always encodes ASCII characters -// as-is. Eventually, this transmutation should be replaced by direct uses of -// OsStr APIs for parsing, but it will take a while for those to become -// available. - -//////////////////////////////////////////////////////////////////////////////// -// Windows Prefixes -//////////////////////////////////////////////////////////////////////////////// - -/// Windows path prefixes, e.g., `C:` or `\\server\share`. -/// -/// Windows uses a variety of path prefix styles, including references to drive -/// volumes (like `C:`), network shared folders (like `\\server\share`), and -/// others. In addition, some path prefixes are "verbatim" (i.e., prefixed with -/// `\\?\`), in which case `/` is *not* treated as a separator and essentially -/// no normalization is performed. -/// -/// # Examples -/// -/// ``` -/// use std::path::{Component, Path, Prefix}; -/// use std::path::Prefix::*; -/// use std::ffi::OsStr; -/// -/// fn get_path_prefix(s: &str) -> Prefix<'_> { -/// let path = Path::new(s); -/// match path.components().next().unwrap() { -/// Component::Prefix(prefix_component) => prefix_component.kind(), -/// _ => panic!(), -/// } -/// } -/// -/// # if cfg!(windows) { -/// assert_eq!(Verbatim(OsStr::new("pictures")), -/// get_path_prefix(r"\\?\pictures\kittens")); -/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")), -/// get_path_prefix(r"\\?\UNC\server\share")); -/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\")); -/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")), -/// get_path_prefix(r"\\.\BrainInterface")); -/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")), -/// get_path_prefix(r"\\server\share")); -/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris")); -/// # } -/// ``` -#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Prefix<'a> { - /// Verbatim prefix, e.g., `\\?\cat_pics`. - /// - /// Verbatim prefixes consist of `\\?\` immediately followed by the given - /// component. - #[stable(feature = "rust1", since = "1.0.0")] - Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - - /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_, - /// e.g., `\\?\UNC\server\share`. - /// - /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the - /// server's hostname and a share name. - #[stable(feature = "rust1", since = "1.0.0")] - VerbatimUNC( - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - ), - - /// Verbatim disk prefix, e.g., `\\?\C:`. - /// - /// Verbatim disk prefixes consist of `\\?\` immediately followed by the - /// drive letter and `:`. - #[stable(feature = "rust1", since = "1.0.0")] - VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8), - - /// Device namespace prefix, e.g., `\\.\COM42`. - /// - /// Device namespace prefixes consist of `\\.\` (possibly using `/` - /// instead of `\`), immediately followed by the device name. - #[stable(feature = "rust1", since = "1.0.0")] - DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), - - /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g. - /// `\\server\share`. - /// - /// UNC prefixes consist of the server's hostname and a share name. - #[stable(feature = "rust1", since = "1.0.0")] - UNC( - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr, - ), - - /// Prefix `C:` for the given disk drive. - #[stable(feature = "rust1", since = "1.0.0")] - Disk(#[stable(feature = "rust1", since = "1.0.0")] u8), -} - -impl<'a> Prefix<'a> { - #[inline] - fn len(&self) -> usize { - use self::Prefix::*; - fn os_str_len(s: &OsStr) -> usize { - s.as_encoded_bytes().len() - } - match *self { - Verbatim(x) => 4 + os_str_len(x), - VerbatimUNC(x, y) => { - 8 + os_str_len(x) + if os_str_len(y) > 0 { 1 + os_str_len(y) } else { 0 } - } - VerbatimDisk(_) => 6, - UNC(x, y) => 2 + os_str_len(x) + if os_str_len(y) > 0 { 1 + os_str_len(y) } else { 0 }, - DeviceNS(x) => 4 + os_str_len(x), - Disk(_) => 2, - } - } - - /// Determines if the prefix is verbatim, i.e., begins with `\\?\`. - /// - /// # Examples - /// - /// ``` - /// use std::path::Prefix::*; - /// use std::ffi::OsStr; - /// - /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim()); - /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); - /// assert!(VerbatimDisk(b'C').is_verbatim()); - /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim()); - /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim()); - /// assert!(!Disk(b'C').is_verbatim()); - /// ``` - #[inline] - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_verbatim(&self) -> bool { - use self::Prefix::*; - matches!(*self, Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..)) - } - - #[inline] - fn is_drive(&self) -> bool { - matches!(*self, Prefix::Disk(_)) - } - - #[inline] - fn has_implicit_root(&self) -> bool { - !self.is_drive() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Exposed parsing helpers -//////////////////////////////////////////////////////////////////////////////// - -/// Determines whether the character is one of the permitted path -/// separators for the current platform. -/// -/// # Examples -/// -/// ``` -/// use std::path; -/// -/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows -/// assert!(!path::is_separator('❤')); -/// ``` -#[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[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) -} - -/// 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 = SEPARATORS[0]; - -/// 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 = SEPARATORS_STR[0]; - -//////////////////////////////////////////////////////////////////////////////// -// Misc helpers -//////////////////////////////////////////////////////////////////////////////// - -// Iterate through `iter` while it matches `prefix`; return `None` if `prefix` -// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving -// `iter` after having exhausted `prefix`. -fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option -where - I: Iterator> + Clone, - J: Iterator>, -{ - loop { - let mut iter_next = iter.clone(); - match (iter_next.next(), prefix.next()) { - (Some(ref x), Some(ref y)) if x == y => (), - (Some(_), Some(_)) => return None, - (Some(_), None) => return Some(iter), - (None, None) => return Some(iter), - (None, Some(_)) => return None, - } - iter = iter_next; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Cross-platform, iterator-independent parsing -//////////////////////////////////////////////////////////////////////////////// - -/// Says whether the first byte after the prefix is a separator. -fn has_physical_root(s: &[u8], prefix: Option>) -> bool { - let path = if let Some(p) = prefix { &s[p.len()..] } else { s }; - !path.is_empty() && is_sep_byte(path[0]) -} - -// basic workhorse for splitting stem and extension -fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - if file.as_encoded_bytes() == b".." { - return (Some(file), None); - } - - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = file.as_encoded_bytes().rsplitn(2, |b| *b == b'.'); - let after = iter.next(); - let before = iter.next(); - if before == Some(b"") { - (Some(file), None) - } else { - unsafe { - ( - before.map(|s| OsStr::from_encoded_bytes_unchecked(s)), - after.map(|s| OsStr::from_encoded_bytes_unchecked(s)), - ) - } - } -} - -fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) { - let slice = file.as_encoded_bytes(); - if slice == b".." { - return (file, None); - } - - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - let i = match slice[1..].iter().position(|b| *b == b'.') { - Some(i) => i + 1, - None => return (file, None), - }; - let before = &slice[..i]; - let after = &slice[i + 1..]; - unsafe { - ( - OsStr::from_encoded_bytes_unchecked(before), - Some(OsStr::from_encoded_bytes_unchecked(after)), - ) - } -} - -/// Checks whether the string is valid as a file extension, or panics otherwise. -fn validate_extension(extension: &OsStr) { - for &b in extension.as_encoded_bytes() { - if is_sep_byte(b) { - panic!("extension cannot contain path separators: {extension:?}"); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// The core iterators -//////////////////////////////////////////////////////////////////////////////// - -/// Component parsing works by a double-ended state machine; the cursors at the -/// front and back of the path each keep track of what parts of the path have -/// been consumed so far. -/// -/// Going front to back, a path is made up of a prefix, a starting -/// directory component, and a body (of normal components) -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -enum State { - Prefix = 0, // c: - StartDir = 1, // / or . or nothing - Body = 2, // foo/bar/baz - Done = 3, -} - -/// A structure wrapping a Windows path prefix as well as its unparsed string -/// representation. -/// -/// In addition to the parsed [`Prefix`] information returned by [`kind`], -/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice, -/// returned by [`as_os_str`]. -/// -/// Instances of this `struct` can be obtained by matching against the -/// [`Prefix` variant] on [`Component`]. -/// -/// Does not occur on Unix. -/// -/// # Examples -/// -/// ``` -/// # if cfg!(windows) { -/// use std::path::{Component, Path, Prefix}; -/// use std::ffi::OsStr; -/// -/// let path = Path::new(r"c:\you\later\"); -/// match path.components().next().unwrap() { -/// Component::Prefix(prefix_component) => { -/// assert_eq!(Prefix::Disk(b'C'), prefix_component.kind()); -/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str()); -/// } -/// _ => unreachable!(), -/// } -/// # } -/// ``` -/// -/// [`as_os_str`]: PrefixComponent::as_os_str -/// [`kind`]: PrefixComponent::kind -/// [`Prefix` variant]: Component::Prefix -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy, Clone, Eq, Debug)] -pub struct PrefixComponent<'a> { - /// The prefix as an unparsed `OsStr` slice. - raw: &'a OsStr, - - /// The parsed prefix data. - parsed: Prefix<'a>, -} - -impl<'a> PrefixComponent<'a> { - /// Returns the parsed prefix data. - /// - /// See [`Prefix`]'s documentation for more information on the different - /// kinds of prefixes. - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn kind(&self) -> Prefix<'a> { - self.parsed - } - - /// Returns the raw [`OsStr`] slice for this prefix. - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn as_os_str(&self) -> &'a OsStr { - self.raw - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> PartialEq for PrefixComponent<'a> { - #[inline] - fn eq(&self, other: &PrefixComponent<'a>) -> bool { - self.parsed == other.parsed - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> PartialOrd for PrefixComponent<'a> { - #[inline] - fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option { - PartialOrd::partial_cmp(&self.parsed, &other.parsed) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for PrefixComponent<'_> { - #[inline] - fn cmp(&self, other: &Self) -> cmp::Ordering { - Ord::cmp(&self.parsed, &other.parsed) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for PrefixComponent<'_> { - fn hash(&self, h: &mut H) { - self.parsed.hash(h); - } -} - -/// A single component of a path. -/// -/// A `Component` roughly corresponds to a substring between path separators -/// (`/` or `\`). -/// -/// This `enum` is created by iterating over [`Components`], which in turn is -/// created by the [`components`](Path::components) method on [`Path`]. -/// -/// # Examples -/// -/// ```rust -/// use std::path::{Component, Path}; -/// -/// let path = Path::new("/tmp/foo/bar.txt"); -/// let components = path.components().collect::>(); -/// assert_eq!(&components, &[ -/// Component::RootDir, -/// Component::Normal("tmp".as_ref()), -/// Component::Normal("foo".as_ref()), -/// Component::Normal("bar.txt".as_ref()), -/// ]); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Component<'a> { - /// A Windows path prefix, e.g., `C:` or `\\server\share`. - /// - /// There is a large variety of prefix types, see [`Prefix`]'s documentation - /// for more. - /// - /// Does not occur on Unix. - #[stable(feature = "rust1", since = "1.0.0")] - Prefix(#[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a>), - - /// The root directory component, appears after any prefix and before anything else. - /// - /// It represents a separator that designates that a path starts from root. - #[stable(feature = "rust1", since = "1.0.0")] - RootDir, - - /// A reference to the current directory, i.e., `.`. - #[stable(feature = "rust1", since = "1.0.0")] - CurDir, - - /// A reference to the parent directory, i.e., `..`. - #[stable(feature = "rust1", since = "1.0.0")] - ParentDir, - - /// A normal component, e.g., `a` and `b` in `a/b`. - /// - /// This variant is the most common one, it represents references to files - /// or directories. - #[stable(feature = "rust1", since = "1.0.0")] - Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), -} - -impl<'a> Component<'a> { - /// Extracts the underlying [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("./tmp/foo/bar.txt"); - /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect(); - /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]); - /// ``` - #[must_use = "`self` will be dropped if the result is not used"] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_os_str(self) -> &'a OsStr { - match self { - Component::Prefix(p) => p.as_os_str(), - Component::RootDir => OsStr::new(MAIN_SEPARATOR_STR), - Component::CurDir => OsStr::new("."), - Component::ParentDir => OsStr::new(".."), - Component::Normal(path) => path, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Component<'_> { - #[inline] - fn as_ref(&self) -> &OsStr { - self.as_os_str() - } -} - -#[stable(feature = "path_component_asref", since = "1.25.0")] -impl AsRef for Component<'_> { - #[inline] - fn as_ref(&self) -> &Path { - self.as_os_str().as_ref() - } -} - -/// An iterator over the [`Component`]s of a [`Path`]. -/// -/// This `struct` is created by the [`components`] method on [`Path`]. -/// See its documentation for more. -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// -/// let path = Path::new("/tmp/foo/bar.txt"); -/// -/// for component in path.components() { -/// println!("{component:?}"); -/// } -/// ``` -/// -/// [`components`]: Path::components -#[derive(Clone)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Components<'a> { - // The path left to parse components from - path: &'a [u8], - - // The prefix as it was originally parsed, if any - prefix: Option>, - - // true if path *physically* has a root separator; for most Windows - // prefixes, it may have a "logical" root separator for the purposes of - // normalization, e.g., \\server\share == \\server\share\. - has_physical_root: bool, - - // The iterator is double-ended, and these two states keep track of what has - // been produced from either end - front: State, - back: State, -} - -/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices. -/// -/// This `struct` is created by the [`iter`] method on [`Path`]. -/// See its documentation for more. -/// -/// [`iter`]: Path::iter -#[derive(Clone)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a> { - inner: Components<'a>, -} - -#[stable(feature = "path_components_debug", since = "1.13.0")] -impl fmt::Debug for Components<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - struct DebugHelper<'a>(&'a Path); - - impl fmt::Debug for DebugHelper<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.0.components()).finish() - } - } - - f.debug_tuple("Components").field(&DebugHelper(self.as_path())).finish() - } -} - -impl<'a> Components<'a> { - // how long is the prefix, if any? - #[inline] - fn prefix_len(&self) -> usize { - if !HAS_PREFIXES { - return 0; - } - self.prefix.as_ref().map(Prefix::len).unwrap_or(0) - } - - #[inline] - fn prefix_verbatim(&self) -> bool { - if !HAS_PREFIXES { - return false; - } - self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false) - } - - /// how much of the prefix is left from the point of view of iteration? - #[inline] - fn prefix_remaining(&self) -> usize { - if !HAS_PREFIXES { - return 0; - } - if self.front == State::Prefix { self.prefix_len() } else { 0 } - } - - // Given the iteration so far, how much of the pre-State::Body path is left? - #[inline] - fn len_before_body(&self) -> usize { - let root = if self.front <= State::StartDir && self.has_physical_root { 1 } else { 0 }; - let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { 1 } else { 0 }; - self.prefix_remaining() + root + cur_dir - } - - // is the iteration complete? - #[inline] - fn finished(&self) -> bool { - self.front == State::Done || self.back == State::Done || self.front > self.back - } - - #[inline] - fn is_sep_byte(&self, b: u8) -> bool { - if self.prefix_verbatim() { is_verbatim_sep(b) } else { is_sep_byte(b) } - } - - /// Extracts a slice corresponding to the portion of the path remaining for iteration. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let mut components = Path::new("/tmp/foo/bar.txt").components(); - /// components.next(); - /// components.next(); - /// - /// assert_eq!(Path::new("foo/bar.txt"), components.as_path()); - /// ``` - #[must_use] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn as_path(&self) -> &'a Path { - let mut comps = self.clone(); - if comps.front == State::Body { - comps.trim_left(); - } - if comps.back == State::Body { - comps.trim_right(); - } - unsafe { Path::from_u8_slice(comps.path) } - } - - /// Is the *original* path rooted? - fn has_root(&self) -> bool { - if self.has_physical_root { - return true; - } - if HAS_PREFIXES && let Some(p) = self.prefix { - if p.has_implicit_root() { - return true; - } - } - false - } - - /// Should the normalized path include a leading . ? - fn include_cur_dir(&self) -> bool { - if self.has_root() { - return false; - } - let slice = &self.path[self.prefix_remaining()..]; - match slice { - [b'.'] => true, - [b'.', b, ..] => self.is_sep_byte(*b), - _ => false, - } - } - - // parse a given byte sequence following the OsStr encoding into the - // corresponding path component - unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option> { - match comp { - b"." if HAS_PREFIXES && self.prefix_verbatim() => Some(Component::CurDir), - b"." => None, // . components are normalized away, except at - // the beginning of a path, which is treated - // separately via `include_cur_dir` - b".." => Some(Component::ParentDir), - b"" => None, - _ => Some(Component::Normal(unsafe { OsStr::from_encoded_bytes_unchecked(comp) })), - } - } - - // parse a component from the left, saying how many bytes to consume to - // remove the component - fn parse_next_component(&self) -> (usize, Option>) { - debug_assert!(self.front == State::Body); - let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) { - None => (0, self.path), - Some(i) => (1, &self.path[..i]), - }; - // SAFETY: `comp` is a valid substring, since it is split on a separator. - (comp.len() + extra, unsafe { self.parse_single_component(comp) }) - } - - // parse a component from the right, saying how many bytes to consume to - // remove the component - fn parse_next_component_back(&self) -> (usize, Option>) { - debug_assert!(self.back == State::Body); - let start = self.len_before_body(); - let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) { - None => (0, &self.path[start..]), - Some(i) => (1, &self.path[start + i + 1..]), - }; - // SAFETY: `comp` is a valid substring, since it is split on a separator. - (comp.len() + extra, unsafe { self.parse_single_component(comp) }) - } - - // trim away repeated separators (i.e., empty components) on the left - fn trim_left(&mut self) { - while !self.path.is_empty() { - let (size, comp) = self.parse_next_component(); - if comp.is_some() { - return; - } else { - self.path = &self.path[size..]; - } - } - } - - // trim away repeated separators (i.e., empty components) on the right - fn trim_right(&mut self) { - while self.path.len() > self.len_before_body() { - let (size, comp) = self.parse_next_component_back(); - if comp.is_some() { - return; - } else { - self.path = &self.path[..self.path.len() - size]; - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Components<'_> { - #[inline] - fn as_ref(&self) -> &Path { - self.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Components<'_> { - #[inline] - fn as_ref(&self) -> &OsStr { - self.as_path().as_os_str() - } -} - -#[stable(feature = "path_iter_debug", since = "1.13.0")] -impl fmt::Debug for Iter<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - struct DebugHelper<'a>(&'a Path); - - impl fmt::Debug for DebugHelper<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.0.iter()).finish() - } - } - - f.debug_tuple("Iter").field(&DebugHelper(self.as_path())).finish() - } -} - -impl<'a> Iter<'a> { - /// Extracts a slice corresponding to the portion of the path remaining for iteration. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let mut iter = Path::new("/tmp/foo/bar.txt").iter(); - /// iter.next(); - /// iter.next(); - /// - /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn as_path(&self) -> &'a Path { - self.inner.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Iter<'_> { - #[inline] - fn as_ref(&self) -> &Path { - self.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for Iter<'_> { - #[inline] - fn as_ref(&self) -> &OsStr { - self.as_path().as_os_str() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Iter<'a> { - type Item = &'a OsStr; - - #[inline] - fn next(&mut self) -> Option<&'a OsStr> { - self.inner.next().map(Component::as_os_str) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Iter<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a OsStr> { - self.inner.next_back().map(Component::as_os_str) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Iter<'_> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Components<'a> { - type Item = Component<'a>; - - fn next(&mut self) -> Option> { - while !self.finished() { - match self.front { - // most likely case first - State::Body if !self.path.is_empty() => { - let (size, comp) = self.parse_next_component(); - self.path = &self.path[size..]; - if comp.is_some() { - return comp; - } - } - State::Body => { - self.front = State::Done; - } - State::StartDir => { - self.front = State::Body; - if self.has_physical_root { - debug_assert!(!self.path.is_empty()); - self.path = &self.path[1..]; - return Some(Component::RootDir); - } else if HAS_PREFIXES && let Some(p) = self.prefix { - if p.has_implicit_root() && !p.is_verbatim() { - return Some(Component::RootDir); - } - } else if self.include_cur_dir() { - debug_assert!(!self.path.is_empty()); - self.path = &self.path[1..]; - return Some(Component::CurDir); - } - } - _ if const { !HAS_PREFIXES } => unreachable!(), - State::Prefix if self.prefix_len() == 0 => { - self.front = State::StartDir; - } - State::Prefix => { - self.front = State::StartDir; - debug_assert!(self.prefix_len() <= self.path.len()); - let raw = &self.path[..self.prefix_len()]; - self.path = &self.path[self.prefix_len()..]; - return Some(Component::Prefix(PrefixComponent { - raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) }, - parsed: self.prefix.unwrap(), - })); - } - State::Done => unreachable!(), - } - } - None - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Components<'a> { - fn next_back(&mut self) -> Option> { - while !self.finished() { - match self.back { - State::Body if self.path.len() > self.len_before_body() => { - let (size, comp) = self.parse_next_component_back(); - self.path = &self.path[..self.path.len() - size]; - if comp.is_some() { - return comp; - } - } - State::Body => { - self.back = State::StartDir; - } - State::StartDir => { - self.back = if HAS_PREFIXES { State::Prefix } else { State::Done }; - if self.has_physical_root { - self.path = &self.path[..self.path.len() - 1]; - return Some(Component::RootDir); - } else if HAS_PREFIXES && let Some(p) = self.prefix { - if p.has_implicit_root() && !p.is_verbatim() { - return Some(Component::RootDir); - } - } else if self.include_cur_dir() { - self.path = &self.path[..self.path.len() - 1]; - return Some(Component::CurDir); - } - } - _ if !HAS_PREFIXES => unreachable!(), - State::Prefix if self.prefix_len() > 0 => { - self.back = State::Done; - return Some(Component::Prefix(PrefixComponent { - raw: unsafe { OsStr::from_encoded_bytes_unchecked(self.path) }, - parsed: self.prefix.unwrap(), - })); - } - State::Prefix => { - self.back = State::Done; - return None; - } - State::Done => unreachable!(), - } - } - None - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Components<'_> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> PartialEq for Components<'a> { - #[inline] - fn eq(&self, other: &Components<'a>) -> bool { - let Components { path: _, front: _, back: _, has_physical_root: _, prefix: _ } = self; - - // Fast path for exact matches, e.g. for hashmap lookups. - // Don't explicitly compare the prefix or has_physical_root fields since they'll - // either be covered by the `path` buffer or are only relevant for `prefix_verbatim()`. - if self.path.len() == other.path.len() - && self.front == other.front - && self.back == State::Body - && other.back == State::Body - && self.prefix_verbatim() == other.prefix_verbatim() - { - // possible future improvement: this could bail out earlier if there were a - // reverse memcmp/bcmp comparing back to front - if self.path == other.path { - return true; - } - } - - // compare back to front since absolute paths often share long prefixes - Iterator::eq(self.clone().rev(), other.clone().rev()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Components<'_> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> PartialOrd for Components<'a> { - #[inline] - fn partial_cmp(&self, other: &Components<'a>) -> Option { - Some(compare_components(self.clone(), other.clone())) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Components<'_> { - #[inline] - fn cmp(&self, other: &Self) -> cmp::Ordering { - compare_components(self.clone(), other.clone()) - } -} - -fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cmp::Ordering { - // Fast path for long shared prefixes - // - // - compare raw bytes to find first mismatch - // - backtrack to find separator before mismatch to avoid ambiguous parsings of '.' or '..' characters - // - if found update state to only do a component-wise comparison on the remainder, - // otherwise do it on the full path - // - // The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into - // the middle of one - if left.prefix.is_none() && right.prefix.is_none() && left.front == right.front { - // possible future improvement: a [u8]::first_mismatch simd implementation - let first_difference = match left.path.iter().zip(right.path).position(|(&a, &b)| a != b) { - None if left.path.len() == right.path.len() => return cmp::Ordering::Equal, - None => left.path.len().min(right.path.len()), - Some(diff) => diff, - }; - - if let Some(previous_sep) = - left.path[..first_difference].iter().rposition(|&b| left.is_sep_byte(b)) - { - let mismatched_component_start = previous_sep + 1; - left.path = &left.path[mismatched_component_start..]; - left.front = State::Body; - right.path = &right.path[mismatched_component_start..]; - right.front = State::Body; - } - } - - Iterator::cmp(left, right) -} - -/// An iterator over [`Path`] and its ancestors. -/// -/// This `struct` is created by the [`ancestors`] method on [`Path`]. -/// See its documentation for more. -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// -/// let path = Path::new("/foo/bar"); -/// -/// for ancestor in path.ancestors() { -/// println!("{}", ancestor.display()); -/// } -/// ``` -/// -/// [`ancestors`]: Path::ancestors -#[derive(Copy, Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "path_ancestors", since = "1.28.0")] -pub struct Ancestors<'a> { - next: Option<&'a Path>, -} - -#[stable(feature = "path_ancestors", since = "1.28.0")] -impl<'a> Iterator for Ancestors<'a> { - type Item = &'a Path; - - #[inline] - fn next(&mut self) -> Option { - let next = self.next; - self.next = next.and_then(Path::parent); - next - } -} - -#[stable(feature = "path_ancestors", since = "1.28.0")] -impl FusedIterator for Ancestors<'_> {} - -//////////////////////////////////////////////////////////////////////////////// -// Basic types and traits -//////////////////////////////////////////////////////////////////////////////// - -/// An owned, mutable path (akin to [`String`]). -/// -/// This type provides methods like [`push`] and [`set_extension`] that mutate -/// the path in place. It also implements [`Deref`] to [`Path`], meaning that -/// all methods on [`Path`] slices are available on `PathBuf` values as well. -/// -/// [`push`]: PathBuf::push -/// [`set_extension`]: PathBuf::set_extension -/// -/// More details about the overall approach can be found in -/// the [module documentation](self). -/// -/// # Examples -/// -/// You can use [`push`] to build up a `PathBuf` from -/// components: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let mut path = PathBuf::new(); -/// -/// path.push(r"C:\"); -/// path.push("windows"); -/// path.push("system32"); -/// -/// path.set_extension("dll"); -/// ``` -/// -/// However, [`push`] is best used for dynamic situations. This is a better way -/// to do this when you know all of the components ahead of time: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect(); -/// ``` -/// -/// We can still do better than this! Since these are all strings, we can use -/// `From::from`: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let path = PathBuf::from(r"C:\windows\system32.dll"); -/// ``` -/// -/// Which method works best depends on what kind of situation you're in. -/// -/// Note that `PathBuf` does not always sanitize arguments, for example -/// [`push`] allows paths built from strings which include separators: -/// -/// ``` -/// use std::path::PathBuf; -/// -/// let mut path = PathBuf::new(); -/// -/// path.push(r"C:\"); -/// path.push("windows"); -/// path.push(r"..\otherdir"); -/// path.push("system32"); -/// ``` -/// -/// The behavior of `PathBuf` may be changed to a panic on such inputs -/// in the future. [`Extend::extend`] should be used to add multi-part paths. -#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct PathBuf { - inner: OsString, -} - -impl PathBuf { - /// Allocates an empty `PathBuf`. - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let path = PathBuf::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "1.91.0")] - pub const fn new() -> PathBuf { - PathBuf { inner: OsString::new() } - } - - /// Creates a new `PathBuf` with a given capacity used to create the - /// internal [`OsString`]. See [`with_capacity`] defined on [`OsString`]. - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::with_capacity(10); - /// let capacity = path.capacity(); - /// - /// // This push is done without reallocating - /// path.push(r"C:\"); - /// - /// assert_eq!(capacity, path.capacity()); - /// ``` - /// - /// [`with_capacity`]: OsString::with_capacity - #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[must_use] - #[inline] - pub fn with_capacity(capacity: usize) -> PathBuf { - PathBuf { inner: OsString::with_capacity(capacity) } - } - - /// Coerces to a [`Path`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let p = PathBuf::from("/test"); - /// assert_eq!(Path::new("/test"), p.as_path()); - /// ``` - #[cfg_attr(not(test), rustc_diagnostic_item = "pathbuf_as_path")] - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn as_path(&self) -> &Path { - self - } - - /// Consumes and leaks the `PathBuf`, returning a mutable reference to the contents, - /// `&'a mut Path`. - /// - /// The caller has free choice over the returned lifetime, including 'static. - /// Indeed, this function is ideally used for data that lives for the remainder of - /// the program's life, as dropping the returned reference will cause a memory leak. - /// - /// It does not reallocate or shrink the `PathBuf`, so the leaked allocation may include - /// unused capacity that is not part of the returned slice. If you want to discard excess - /// capacity, call [`into_boxed_path`], and then [`Box::leak`] instead. - /// However, keep in mind that trimming the capacity may result in a reallocation and copy. - /// - /// [`into_boxed_path`]: Self::into_boxed_path - #[stable(feature = "os_string_pathbuf_leak", since = "1.89.0")] - #[inline] - pub fn leak<'a>(self) -> &'a mut Path { - Path::from_inner_mut(self.inner.leak()) - } - - /// Extends `self` with `path`. - /// - /// If `path` is absolute, it replaces the current path. - /// - /// On Windows: - /// - /// * if `path` has a root but no prefix (e.g., `\windows`), it - /// replaces everything except for the prefix (if any) of `self`. - /// * if `path` has a prefix but no root, it replaces `self`. - /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`) - /// and `path` is not empty, the new path is normalized: all references - /// to `.` and `..` are removed. - /// - /// Consider using [`Path::join`] if you need a new `PathBuf` instead of - /// using this function on a cloned `PathBuf`. - /// - /// # Examples - /// - /// Pushing a relative path extends the existing path: - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::from("/tmp"); - /// path.push("file.bk"); - /// assert_eq!(path, PathBuf::from("/tmp/file.bk")); - /// ``` - /// - /// Pushing an absolute path replaces the existing path: - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut path = PathBuf::from("/tmp"); - /// path.push("/etc"); - /// assert_eq!(path, PathBuf::from("/etc")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_confusables("append", "put")] - pub fn push>(&mut self, path: P) { - self._push(path.as_ref()) - } - - fn _push(&mut self, path: &Path) { - // in general, a separator is needed if the rightmost byte is not a separator - let buf = self.inner.as_encoded_bytes(); - let mut need_sep = buf.last().map(|c| !is_sep_byte(*c)).unwrap_or(false); - - // in the special case of `C:` on Windows, do *not* add a separator - let comps = self.components(); - - if comps.prefix_len() > 0 - && comps.prefix_len() == comps.path.len() - && comps.prefix.unwrap().is_drive() - { - need_sep = false - } - - let need_clear = if cfg!(target_os = "cygwin") { - // If path is absolute and its prefix is none, it is like `/foo`, - // and will be handled below. - path.prefix().is_some() - } else { - // On Unix: prefix is always None. - path.is_absolute() || path.prefix().is_some() - }; - - // absolute `path` replaces `self` - if need_clear { - self.inner.truncate(0); - - // verbatim paths need . and .. removed - } else if comps.prefix_verbatim() && !path.inner.is_empty() { - let mut buf: Vec<_> = comps.collect(); - for c in path.components() { - match c { - Component::RootDir => { - buf.truncate(1); - buf.push(c); - } - Component::CurDir => (), - Component::ParentDir => { - if let Some(Component::Normal(_)) = buf.last() { - buf.pop(); - } - } - _ => buf.push(c), - } - } - - let mut res = OsString::new(); - let mut need_sep = false; - - for c in buf { - if need_sep && c != Component::RootDir { - res.push(MAIN_SEPARATOR_STR); - } - res.push(c.as_os_str()); - - need_sep = match c { - Component::RootDir => false, - Component::Prefix(prefix) => { - !prefix.parsed.is_drive() && prefix.parsed.len() > 0 - } - _ => true, - } - } - - self.inner = res; - return; - - // `path` has a root but no prefix, e.g., `\windows` (Windows only) - } else if path.has_root() { - let prefix_len = self.components().prefix_remaining(); - self.inner.truncate(prefix_len); - - // `path` is a pure relative path - } else if need_sep { - self.inner.push(MAIN_SEPARATOR_STR); - } - - self.inner.push(path); - } - - /// Truncates `self` to [`self.parent`]. - /// - /// Returns `false` and does nothing if [`self.parent`] is [`None`]. - /// Otherwise, returns `true`. - /// - /// [`self.parent`]: Path::parent - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut p = PathBuf::from("/spirited/away.rs"); - /// - /// p.pop(); - /// assert_eq!(Path::new("/spirited"), p); - /// p.pop(); - /// assert_eq!(Path::new("/"), p); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop(&mut self) -> bool { - match self.parent().map(|p| p.as_u8_slice().len()) { - Some(len) => { - self.inner.truncate(len); - true - } - None => false, - } - } - - /// Sets whether the path has a trailing [separator](MAIN_SEPARATOR). - /// - /// The value returned by [`has_trailing_sep`](Path::has_trailing_sep) will be equivalent to - /// the provided value if possible. - /// - /// # Examples - /// - /// ``` - /// #![feature(path_trailing_sep)] - /// use std::path::PathBuf; - /// - /// let mut p = PathBuf::from("dir"); - /// - /// assert!(!p.has_trailing_sep()); - /// p.set_trailing_sep(false); - /// assert!(!p.has_trailing_sep()); - /// p.set_trailing_sep(true); - /// assert!(p.has_trailing_sep()); - /// p.set_trailing_sep(false); - /// assert!(!p.has_trailing_sep()); - /// - /// p = PathBuf::from("/"); - /// assert!(p.has_trailing_sep()); - /// p.set_trailing_sep(false); - /// assert!(p.has_trailing_sep()); - /// ``` - #[unstable(feature = "path_trailing_sep", issue = "142503")] - pub fn set_trailing_sep(&mut self, trailing_sep: bool) { - if trailing_sep { self.push_trailing_sep() } else { self.pop_trailing_sep() } - } - - /// Adds a trailing [separator](MAIN_SEPARATOR) to the path. - /// - /// This acts similarly to [`Path::with_trailing_sep`], but mutates the underlying `PathBuf`. - /// - /// # Examples - /// - /// ``` - /// #![feature(path_trailing_sep)] - /// use std::ffi::OsStr; - /// use std::path::PathBuf; - /// - /// let mut p = PathBuf::from("dir"); - /// - /// assert!(!p.has_trailing_sep()); - /// p.push_trailing_sep(); - /// assert!(p.has_trailing_sep()); - /// p.push_trailing_sep(); - /// assert!(p.has_trailing_sep()); - /// - /// p = PathBuf::from("dir/"); - /// p.push_trailing_sep(); - /// assert_eq!(p.as_os_str(), OsStr::new("dir/")); - /// ``` - #[unstable(feature = "path_trailing_sep", issue = "142503")] - pub fn push_trailing_sep(&mut self) { - if !self.has_trailing_sep() { - self.push(""); - } - } - - /// Removes a trailing [separator](MAIN_SEPARATOR) from the path, if possible. - /// - /// This acts similarly to [`Path::trim_trailing_sep`], but mutates the underlying `PathBuf`. - /// - /// # Examples - /// - /// ``` - /// #![feature(path_trailing_sep)] - /// use std::ffi::OsStr; - /// use std::path::PathBuf; - /// - /// let mut p = PathBuf::from("dir//"); - /// - /// assert!(p.has_trailing_sep()); - /// assert_eq!(p.as_os_str(), OsStr::new("dir//")); - /// p.pop_trailing_sep(); - /// assert!(!p.has_trailing_sep()); - /// assert_eq!(p.as_os_str(), OsStr::new("dir")); - /// p.pop_trailing_sep(); - /// assert!(!p.has_trailing_sep()); - /// assert_eq!(p.as_os_str(), OsStr::new("dir")); - /// - /// p = PathBuf::from("/"); - /// assert!(p.has_trailing_sep()); - /// p.pop_trailing_sep(); - /// assert!(p.has_trailing_sep()); - /// ``` - #[unstable(feature = "path_trailing_sep", issue = "142503")] - pub fn pop_trailing_sep(&mut self) { - self.inner.truncate(self.trim_trailing_sep().as_os_str().len()); - } - - /// Updates [`self.file_name`] to `file_name`. - /// - /// If [`self.file_name`] was [`None`], this is equivalent to pushing - /// `file_name`. - /// - /// Otherwise it is equivalent to calling [`pop`] and then pushing - /// `file_name`. The new path will be a sibling of the original path. - /// (That is, it will have the same parent.) - /// - /// The argument is not sanitized, so can include separators. This - /// behavior may be changed to a panic in the future. - /// - /// [`self.file_name`]: Path::file_name - /// [`pop`]: PathBuf::pop - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let mut buf = PathBuf::from("/"); - /// assert!(buf.file_name() == None); - /// - /// buf.set_file_name("foo.txt"); - /// assert!(buf == PathBuf::from("/foo.txt")); - /// assert!(buf.file_name().is_some()); - /// - /// buf.set_file_name("bar.txt"); - /// assert!(buf == PathBuf::from("/bar.txt")); - /// - /// buf.set_file_name("baz"); - /// assert!(buf == PathBuf::from("/baz")); - /// - /// buf.set_file_name("../b/c.txt"); - /// assert!(buf == PathBuf::from("/../b/c.txt")); - /// - /// buf.set_file_name("baz"); - /// assert!(buf == PathBuf::from("/../b/baz")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_file_name>(&mut self, file_name: S) { - self._set_file_name(file_name.as_ref()) - } - - fn _set_file_name(&mut self, file_name: &OsStr) { - if self.file_name().is_some() { - let popped = self.pop(); - debug_assert!(popped); - } - self.push(file_name); - } - - /// Updates [`self.extension`] to `Some(extension)` or to `None` if - /// `extension` is empty. - /// - /// Returns `false` and does nothing if [`self.file_name`] is [`None`], - /// returns `true` and updates the extension otherwise. - /// - /// If [`self.extension`] is [`None`], the extension is added; otherwise - /// it is replaced. - /// - /// If `extension` is the empty string, [`self.extension`] will be [`None`] - /// afterwards, not `Some("")`. - /// - /// # Panics - /// - /// Panics if the passed extension contains a path separator (see - /// [`is_separator`]). - /// - /// # Caveats - /// - /// The new `extension` may contain dots and will be used in its entirety, - /// but only the part after the final dot will be reflected in - /// [`self.extension`]. - /// - /// If the file stem contains internal dots and `extension` is empty, part - /// of the old file stem will be considered the new [`self.extension`]. - /// - /// See the examples below. - /// - /// [`self.file_name`]: Path::file_name - /// [`self.extension`]: Path::extension - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut p = PathBuf::from("/feel/the"); - /// - /// p.set_extension("force"); - /// assert_eq!(Path::new("/feel/the.force"), p.as_path()); - /// - /// p.set_extension("dark.side"); - /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path()); - /// - /// p.set_extension("cookie"); - /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path()); - /// - /// p.set_extension(""); - /// assert_eq!(Path::new("/feel/the.dark"), p.as_path()); - /// - /// p.set_extension(""); - /// assert_eq!(Path::new("/feel/the"), p.as_path()); - /// - /// p.set_extension(""); - /// assert_eq!(Path::new("/feel/the"), p.as_path()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_extension>(&mut self, extension: S) -> bool { - self._set_extension(extension.as_ref()) - } - - fn _set_extension(&mut self, extension: &OsStr) -> bool { - validate_extension(extension); - - let file_stem = match self.file_stem() { - None => return false, - Some(f) => f.as_encoded_bytes(), - }; - - // truncate until right after the file stem - let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr(); - let start = self.inner.as_encoded_bytes().as_ptr().addr(); - self.inner.truncate(end_file_stem.wrapping_sub(start)); - - // add the new extension, if any - let new = extension.as_encoded_bytes(); - if !new.is_empty() { - self.inner.reserve_exact(new.len() + 1); - self.inner.push("."); - // SAFETY: Since a UTF-8 string was just pushed, it is not possible - // for the buffer to end with a surrogate half. - unsafe { self.inner.extend_from_slice_unchecked(new) }; - } - - true - } - - /// Append [`self.extension`] with `extension`. - /// - /// Returns `false` and does nothing if [`self.file_name`] is [`None`], - /// returns `true` and updates the extension otherwise. - /// - /// # Panics - /// - /// Panics if the passed extension contains a path separator (see - /// [`is_separator`]). - /// - /// # Caveats - /// - /// The appended `extension` may contain dots and will be used in its entirety, - /// but only the part after the final dot will be reflected in - /// [`self.extension`]. - /// - /// See the examples below. - /// - /// [`self.file_name`]: Path::file_name - /// [`self.extension`]: Path::extension - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut p = PathBuf::from("/feel/the"); - /// - /// p.add_extension("formatted"); - /// assert_eq!(Path::new("/feel/the.formatted"), p.as_path()); - /// - /// p.add_extension("dark.side"); - /// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path()); - /// - /// p.set_extension("cookie"); - /// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path()); - /// - /// p.set_extension(""); - /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); - /// - /// p.add_extension(""); - /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path()); - /// ``` - #[stable(feature = "path_add_extension", since = "1.91.0")] - pub fn add_extension>(&mut self, extension: S) -> bool { - self._add_extension(extension.as_ref()) - } - - fn _add_extension(&mut self, extension: &OsStr) -> bool { - validate_extension(extension); - - let file_name = match self.file_name() { - None => return false, - Some(f) => f.as_encoded_bytes(), - }; - - let new = extension.as_encoded_bytes(); - if !new.is_empty() { - // truncate until right after the file name - // this is necessary for trimming the trailing separator - let end_file_name = file_name[file_name.len()..].as_ptr().addr(); - let start = self.inner.as_encoded_bytes().as_ptr().addr(); - self.inner.truncate(end_file_name.wrapping_sub(start)); - - // append the new extension - self.inner.reserve_exact(new.len() + 1); - self.inner.push("."); - // SAFETY: Since a UTF-8 string was just pushed, it is not possible - // for the buffer to end with a surrogate half. - unsafe { self.inner.extend_from_slice_unchecked(new) }; - } - - true - } - - /// Yields a mutable reference to the underlying [`OsString`] instance. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut path = PathBuf::from("/foo"); - /// - /// path.push("bar"); - /// assert_eq!(path, Path::new("/foo/bar")); - /// - /// // OsString's `push` does not add a separator. - /// path.as_mut_os_string().push("baz"); - /// assert_eq!(path, Path::new("/foo/barbaz")); - /// ``` - #[stable(feature = "path_as_mut_os_str", since = "1.70.0")] - #[must_use] - #[inline] - pub fn as_mut_os_string(&mut self) -> &mut OsString { - &mut self.inner - } - - /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage. - /// - /// # Examples - /// - /// ``` - /// use std::path::PathBuf; - /// - /// let p = PathBuf::from("/the/head"); - /// let os_str = p.into_os_string(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "`self` will be dropped if the result is not used"] - #[inline] - pub fn into_os_string(self) -> OsString { - self.inner - } - - /// Converts this `PathBuf` into a [boxed](Box) [`Path`]. - #[stable(feature = "into_boxed_path", since = "1.20.0")] - #[must_use = "`self` will be dropped if the result is not used"] - #[inline] - pub fn into_boxed_path(self) -> Box { - let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; - unsafe { Box::from_raw(rw) } - } - - /// Invokes [`capacity`] on the underlying instance of [`OsString`]. - /// - /// [`capacity`]: OsString::capacity - #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[must_use] - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - /// Invokes [`clear`] on the underlying instance of [`OsString`]. - /// - /// [`clear`]: OsString::clear - #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - /// Invokes [`reserve`] on the underlying instance of [`OsString`]. - /// - /// [`reserve`]: OsString::reserve - #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - /// Invokes [`try_reserve`] on the underlying instance of [`OsString`]. - /// - /// [`try_reserve`]: OsString::try_reserve - #[stable(feature = "try_reserve_2", since = "1.63.0")] - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.inner.try_reserve(additional) - } - - /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`]. - /// - /// [`reserve_exact`]: OsString::reserve_exact - #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - /// Invokes [`try_reserve_exact`] on the underlying instance of [`OsString`]. - /// - /// [`try_reserve_exact`]: OsString::try_reserve_exact - #[stable(feature = "try_reserve_2", since = "1.63.0")] - #[inline] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.inner.try_reserve_exact(additional) - } - - /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`]. - /// - /// [`shrink_to_fit`]: OsString::shrink_to_fit - #[stable(feature = "path_buf_capacity", since = "1.44.0")] - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - /// Invokes [`shrink_to`] on the underlying instance of [`OsString`]. - /// - /// [`shrink_to`]: OsString::shrink_to - #[stable(feature = "shrink_to", since = "1.56.0")] - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for PathBuf { - #[inline] - fn clone(&self) -> Self { - PathBuf { inner: self.inner.clone() } - } - - /// Clones the contents of `source` into `self`. - /// - /// This method is preferred over simply assigning `source.clone()` to `self`, - /// as it avoids reallocation if possible. - #[inline] - fn clone_from(&mut self, source: &Self) { - self.inner.clone_from(&source.inner) - } -} - -#[stable(feature = "box_from_path", since = "1.17.0")] -impl From<&Path> for Box { - /// Creates a boxed [`Path`] from a reference. - /// - /// This will allocate and clone `path` to it. - fn from(path: &Path) -> Box { - Box::clone_from_ref(path) - } -} - -#[stable(feature = "box_from_mut_slice", since = "1.84.0")] -impl From<&mut Path> for Box { - /// Creates a boxed [`Path`] from a reference. - /// - /// This will allocate and clone `path` to it. - fn from(path: &mut Path) -> Box { - Self::from(&*path) - } -} - -#[stable(feature = "box_from_cow", since = "1.45.0")] -impl From> for Box { - /// Creates a boxed [`Path`] from a clone-on-write pointer. - /// - /// Converting from a `Cow::Owned` does not clone or allocate. - #[inline] - fn from(cow: Cow<'_, Path>) -> Box { - match cow { - Cow::Borrowed(path) => Box::from(path), - Cow::Owned(path) => Box::from(path), - } - } -} - -#[stable(feature = "path_buf_from_box", since = "1.18.0")] -impl From> for PathBuf { - /// Converts a [Box]<[Path]> into a [`PathBuf`]. - /// - /// This conversion does not allocate or copy memory. - #[inline] - fn from(boxed: Box) -> PathBuf { - boxed.into_path_buf() - } -} - -#[stable(feature = "box_from_path_buf", since = "1.20.0")] -impl From for Box { - /// Converts a [`PathBuf`] into a [Box]<[Path]>. - /// - /// This conversion currently should not allocate memory, - /// but this behavior is not guaranteed on all platforms or in all future versions. - #[inline] - fn from(p: PathBuf) -> Box { - p.into_boxed_path() - } -} - -#[stable(feature = "more_box_slice_clone", since = "1.29.0")] -impl Clone for Box { - #[inline] - fn clone(&self) -> Self { - self.to_path_buf().into_boxed_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl> From<&T> for PathBuf { - /// Converts a borrowed [`OsStr`] to a [`PathBuf`]. - /// - /// Allocates a [`PathBuf`] and copies the data into it. - #[inline] - fn from(s: &T) -> PathBuf { - PathBuf::from(s.as_ref().to_os_string()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for PathBuf { - /// Converts an [`OsString`] into a [`PathBuf`]. - /// - /// This conversion does not allocate or copy memory. - #[inline] - fn from(s: OsString) -> PathBuf { - PathBuf { inner: s } - } -} - -#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")] -impl From for OsString { - /// Converts a [`PathBuf`] into an [`OsString`] - /// - /// This conversion does not allocate or copy memory. - #[inline] - fn from(path_buf: PathBuf) -> OsString { - path_buf.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl From for PathBuf { - /// Converts a [`String`] into a [`PathBuf`] - /// - /// This conversion does not allocate or copy memory. - #[inline] - fn from(s: String) -> PathBuf { - PathBuf::from(OsString::from(s)) - } -} - -#[stable(feature = "path_from_str", since = "1.32.0")] -impl FromStr for PathBuf { - type Err = core::convert::Infallible; - - #[inline] - fn from_str(s: &str) -> Result { - Ok(PathBuf::from(s)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl> FromIterator

for PathBuf { - /// Creates a new `PathBuf` from the [`Path`] elements of an iterator. - /// - /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path - /// [components](Components). - /// - /// # Examples - /// ``` - /// # use std::path::PathBuf; - /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]); - /// assert_eq!(path, PathBuf::from("/tmp/foo/bar")); - /// ``` - /// - /// See documentation for [`push`](Self::push) for more details on how the path is constructed. - fn from_iter>(iter: I) -> PathBuf { - let mut buf = PathBuf::new(); - buf.extend(iter); - buf - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl> Extend

for PathBuf { - /// Extends `self` with [`Path`] elements from `iter`. - /// - /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path - /// [components](Components). - /// - /// # Examples - /// ``` - /// # use std::path::PathBuf; - /// let mut path = PathBuf::from("/tmp"); - /// path.extend(["foo", "bar", "file.txt"]); - /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt")); - /// ``` - /// - /// See documentation for [`push`](Self::push) for more details on how the path is constructed. - fn extend>(&mut self, iter: I) { - iter.into_iter().for_each(move |p| self.push(p.as_ref())); - } - - #[inline] - fn extend_one(&mut self, p: P) { - self.push(p.as_ref()); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for PathBuf { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, formatter) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for PathBuf { - type Target = Path; - #[inline] - fn deref(&self) -> &Path { - Path::new(&self.inner) - } -} - -#[stable(feature = "path_buf_deref_mut", since = "1.68.0")] -impl ops::DerefMut for PathBuf { - #[inline] - fn deref_mut(&mut self) -> &mut Path { - Path::from_inner_mut(&mut self.inner) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for PathBuf { - #[inline] - fn borrow(&self) -> &Path { - self.deref() - } -} - -#[stable(feature = "default_for_pathbuf", since = "1.17.0")] -impl Default for PathBuf { - #[inline] - fn default() -> Self { - PathBuf::new() - } -} - -#[stable(feature = "cow_from_path", since = "1.6.0")] -impl<'a> From<&'a Path> for Cow<'a, Path> { - /// Creates a clone-on-write pointer from a reference to - /// [`Path`]. - /// - /// This conversion does not clone or allocate. - #[inline] - fn from(s: &'a Path) -> Cow<'a, Path> { - Cow::Borrowed(s) - } -} - -#[stable(feature = "cow_from_path", since = "1.6.0")] -impl<'a> From for Cow<'a, Path> { - /// Creates a clone-on-write pointer from an owned - /// instance of [`PathBuf`]. - /// - /// This conversion does not clone or allocate. - #[inline] - fn from(s: PathBuf) -> Cow<'a, Path> { - Cow::Owned(s) - } -} - -#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")] -impl<'a> From<&'a PathBuf> for Cow<'a, Path> { - /// Creates a clone-on-write pointer from a reference to - /// [`PathBuf`]. - /// - /// This conversion does not clone or allocate. - #[inline] - fn from(p: &'a PathBuf) -> Cow<'a, Path> { - Cow::Borrowed(p.as_path()) - } -} - -#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")] -impl<'a> From> for PathBuf { - /// Converts a clone-on-write pointer to an owned path. - /// - /// Converting from a `Cow::Owned` does not clone or allocate. - #[inline] - fn from(p: Cow<'a, Path>) -> Self { - p.into_owned() - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Arc { - /// Converts a [`PathBuf`] into an [Arc]<[Path]> by moving the [`PathBuf`] data - /// into a new [`Arc`] buffer. - #[inline] - fn from(s: PathBuf) -> Arc { - let arc: Arc = Arc::from(s.into_os_string()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From<&Path> for Arc { - /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer. - #[inline] - fn from(s: &Path) -> Arc { - let arc: Arc = Arc::from(s.as_os_str()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) } - } -} - -#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] -impl From<&mut Path> for Arc { - /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer. - #[inline] - fn from(s: &mut Path) -> Arc { - Arc::from(&*s) - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From for Rc { - /// Converts a [`PathBuf`] into an [Rc]<[Path]> by moving the [`PathBuf`] data into - /// a new [`Rc`] buffer. - #[inline] - fn from(s: PathBuf) -> Rc { - let rc: Rc = Rc::from(s.into_os_string()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } - } -} - -#[stable(feature = "shared_from_slice2", since = "1.24.0")] -impl From<&Path> for Rc { - /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer. - #[inline] - fn from(s: &Path) -> Rc { - let rc: Rc = Rc::from(s.as_os_str()); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) } - } -} - -#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] -impl From<&mut Path> for Rc { - /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer. - #[inline] - fn from(s: &mut Path) -> Rc { - Rc::from(&*s) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToOwned for Path { - type Owned = PathBuf; - #[inline] - fn to_owned(&self) -> PathBuf { - self.to_path_buf() - } - #[inline] - fn clone_into(&self, target: &mut PathBuf) { - self.inner.clone_into(&mut target.inner); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for PathBuf { - #[inline] - fn eq(&self, other: &PathBuf) -> bool { - self.components() == other.components() - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for PathBuf { - #[inline] - fn eq(&self, other: &str) -> bool { - self.as_path() == other - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for str { - #[inline] - fn eq(&self, other: &PathBuf) -> bool { - self == other.as_path() - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for PathBuf { - #[inline] - fn eq(&self, other: &String) -> bool { - self.as_path() == other.as_str() - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for String { - #[inline] - fn eq(&self, other: &PathBuf) -> bool { - self.as_str() == other.as_path() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for PathBuf { - fn hash(&self, h: &mut H) { - self.as_path().hash(h) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for PathBuf {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for PathBuf { - #[inline] - fn partial_cmp(&self, other: &PathBuf) -> Option { - Some(compare_components(self.components(), other.components())) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for PathBuf { - #[inline] - fn cmp(&self, other: &PathBuf) -> cmp::Ordering { - compare_components(self.components(), other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for PathBuf { - #[inline] - fn as_ref(&self) -> &OsStr { - &self.inner[..] - } -} - -/// A slice of a path (akin to [`str`]). -/// -/// This type supports a number of operations for inspecting a path, including -/// breaking the path into its components (separated by `/` on Unix and by either -/// `/` or `\` on Windows), extracting the file name, determining whether the path -/// is absolute, and so on. -/// -/// This is an *unsized* type, meaning that it must always be used behind a -/// pointer like `&` or [`Box`]. For an owned version of this type, -/// see [`PathBuf`]. -/// -/// More details about the overall approach can be found in -/// the [module documentation](self). -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// use std::ffi::OsStr; -/// -/// // Note: this example does work on Windows -/// let path = Path::new("./foo/bar.txt"); -/// -/// let parent = path.parent(); -/// assert_eq!(parent, Some(Path::new("./foo"))); -/// -/// let file_stem = path.file_stem(); -/// assert_eq!(file_stem, Some(OsStr::new("bar"))); -/// -/// let extension = path.extension(); -/// assert_eq!(extension, Some(OsStr::new("txt"))); -/// ``` -#[cfg_attr(not(test), rustc_diagnostic_item = "Path")] -#[stable(feature = "rust1", since = "1.0.0")] -// `Path::new` and `impl CloneToUninit for Path` current implementation relies -// on `Path` being layout-compatible with `OsStr`. -// However, `Path` layout is considered an implementation detail and must not be relied upon. -#[repr(transparent)] -pub struct Path { - inner: OsStr, -} - -/// An error returned from [`Path::strip_prefix`] if the prefix was not found. -/// -/// This `struct` is created by the [`strip_prefix`] method on [`Path`]. -/// See its documentation for more. -/// -/// [`strip_prefix`]: Path::strip_prefix -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(since = "1.7.0", feature = "strip_prefix")] -pub struct StripPrefixError(()); - -/// An error returned from [`Path::normalize_lexically`] if a `..` parent reference -/// would escape the path. -#[unstable(feature = "normalize_lexically", issue = "134694")] -#[derive(Debug, PartialEq)] -#[non_exhaustive] -pub struct NormalizeError; - -impl Path { - // The following (private!) function allows construction of a path from a u8 - // slice, which is only safe when it is known to follow the OsStr encoding. - unsafe fn from_u8_slice(s: &[u8]) -> &Path { - unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) } - } - // The following (private!) function reveals the byte encoding used for OsStr. - pub(crate) fn as_u8_slice(&self) -> &[u8] { - self.inner.as_encoded_bytes() - } - - /// Directly wraps a string slice as a `Path` slice. - /// - /// This is a cost-free conversion. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// Path::new("foo.txt"); - /// ``` - /// - /// You can create `Path`s from `String`s, or even other `Path`s: - /// - /// ``` - /// use std::path::Path; - /// - /// let string = String::from("foo.txt"); - /// let from_string = Path::new(&string); - /// let from_path = Path::new(&from_string); - /// assert_eq!(from_string, from_path); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - pub const fn new + ?Sized>(s: &S) -> &Path { - unsafe { &*(s.as_ref() as *const OsStr as *const Path) } - } - - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - const fn from_inner_mut(inner: &mut OsStr) -> &mut Path { - // SAFETY: Path is just a wrapper around OsStr, - // therefore converting &mut OsStr to &mut Path is safe. - unsafe { &mut *(inner as *mut OsStr as *mut Path) } - } - - /// Yields the underlying [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let os_str = Path::new("foo.txt").as_os_str(); - /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn as_os_str(&self) -> &OsStr { - &self.inner - } - - /// Yields a mutable reference to the underlying [`OsStr`] slice. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let mut path = PathBuf::from("Foo.TXT"); - /// - /// assert_ne!(path, Path::new("foo.txt")); - /// - /// path.as_mut_os_str().make_ascii_lowercase(); - /// assert_eq!(path, Path::new("foo.txt")); - /// ``` - #[stable(feature = "path_as_mut_os_str", since = "1.70.0")] - #[must_use] - #[inline] - pub fn as_mut_os_str(&mut self) -> &mut OsStr { - &mut self.inner - } - - /// Yields a [`&str`] slice if the `Path` is valid unicode. - /// - /// This conversion may entail doing a check for UTF-8 validity. - /// Note that validation is performed because non-UTF-8 strings are - /// perfectly valid for some OS. - /// - /// [`&str`]: str - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.txt"); - /// assert_eq!(path.to_str(), Some("foo.txt")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub fn to_str(&self) -> Option<&str> { - self.inner.to_str() - } - - /// Converts a `Path` to a [`Cow`]. - /// - /// Any non-UTF-8 sequences are replaced with - /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. - /// - /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER - /// - /// # Examples - /// - /// Calling `to_string_lossy` on a `Path` with valid unicode: - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.txt"); - /// assert_eq!(path.to_string_lossy(), "foo.txt"); - /// ``` - /// - /// Had `path` contained invalid unicode, the `to_string_lossy` call might - /// have returned `"fo�.txt"`. - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub fn to_string_lossy(&self) -> Cow<'_, str> { - self.inner.to_string_lossy() - } - - /// Converts a `Path` to an owned [`PathBuf`]. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path_buf = Path::new("foo.txt").to_path_buf(); - /// assert_eq!(path_buf, PathBuf::from("foo.txt")); - /// ``` - #[rustc_conversion_suggestion] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "path_to_pathbuf")] - pub fn to_path_buf(&self) -> PathBuf { - PathBuf::from(self.inner.to_os_string()) - } - - /// Returns `true` if the `Path` is absolute, i.e., if it is independent of - /// the current directory. - /// - /// * On Unix, a path is absolute if it starts with the root, so - /// `is_absolute` and [`has_root`] are equivalent. - /// - /// * On Windows, a path is absolute if it has a prefix and starts with the - /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert!(!Path::new("foo.txt").is_absolute()); - /// ``` - /// - /// [`has_root`]: Path::has_root - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[allow(deprecated)] - pub fn is_absolute(&self) -> bool { - sys::path::is_absolute(self) - } - - /// Returns `true` if the `Path` is relative, i.e., not absolute. - /// - /// See [`is_absolute`]'s documentation for more details. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert!(Path::new("foo.txt").is_relative()); - /// ``` - /// - /// [`is_absolute`]: Path::is_absolute - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn is_relative(&self) -> bool { - !self.is_absolute() - } - - pub(crate) fn prefix(&self) -> Option> { - self.components().prefix - } - - /// Returns `true` if the `Path` has a root. - /// - /// * On Unix, a path has a root if it begins with `/`. - /// - /// * On Windows, a path has a root if it: - /// * has no prefix and begins with a separator, e.g., `\windows` - /// * has a prefix followed by a separator, e.g., `c:\windows` but not `c:windows` - /// * has any non-disk prefix, e.g., `\\server\share` - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert!(Path::new("/etc/passwd").has_root()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - #[inline] - pub fn has_root(&self) -> bool { - self.components().has_root() - } - - /// Returns the `Path` without its final component, if there is one. - /// - /// This means it returns `Some("")` for relative paths with one component. - /// - /// Returns [`None`] if the path terminates in a root or prefix, or if it's - /// the empty string. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/foo/bar"); - /// let parent = path.parent().unwrap(); - /// assert_eq!(parent, Path::new("/foo")); - /// - /// let grand_parent = parent.parent().unwrap(); - /// assert_eq!(grand_parent, Path::new("/")); - /// assert_eq!(grand_parent.parent(), None); - /// - /// let relative_path = Path::new("foo/bar"); - /// let parent = relative_path.parent(); - /// assert_eq!(parent, Some(Path::new("foo"))); - /// let grand_parent = parent.and_then(Path::parent); - /// assert_eq!(grand_parent, Some(Path::new(""))); - /// let great_grand_parent = grand_parent.and_then(Path::parent); - /// assert_eq!(great_grand_parent, None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[doc(alias = "dirname")] - #[must_use] - pub fn parent(&self) -> Option<&Path> { - let mut comps = self.components(); - let comp = comps.next_back(); - comp.and_then(|p| match p { - Component::Normal(_) | Component::CurDir | Component::ParentDir => { - Some(comps.as_path()) - } - _ => None, - }) - } - - /// Produces an iterator over `Path` and its ancestors. - /// - /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero - /// or more times. If the [`parent`] method returns [`None`], the iterator will do likewise. - /// The iterator will always yield at least one value, namely `Some(&self)`. Next it will yield - /// `&self.parent()`, `&self.parent().and_then(Path::parent)` and so on. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let mut ancestors = Path::new("/foo/bar").ancestors(); - /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar"))); - /// assert_eq!(ancestors.next(), Some(Path::new("/foo"))); - /// assert_eq!(ancestors.next(), Some(Path::new("/"))); - /// assert_eq!(ancestors.next(), None); - /// - /// let mut ancestors = Path::new("../foo/bar").ancestors(); - /// assert_eq!(ancestors.next(), Some(Path::new("../foo/bar"))); - /// assert_eq!(ancestors.next(), Some(Path::new("../foo"))); - /// assert_eq!(ancestors.next(), Some(Path::new(".."))); - /// assert_eq!(ancestors.next(), Some(Path::new(""))); - /// assert_eq!(ancestors.next(), None); - /// ``` - /// - /// [`parent`]: Path::parent - #[stable(feature = "path_ancestors", since = "1.28.0")] - #[inline] - pub fn ancestors(&self) -> Ancestors<'_> { - Ancestors { next: Some(&self) } - } - - /// Returns the final component of the `Path`, if there is one. - /// - /// If the path is a normal file, this is the file name. If it's the path of a directory, this - /// is the directory name. - /// - /// Returns [`None`] if the path terminates in `..`. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// use std::ffi::OsStr; - /// - /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name()); - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); - /// assert_eq!(None, Path::new("foo.txt/..").file_name()); - /// assert_eq!(None, Path::new("/").file_name()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[doc(alias = "basename")] - #[must_use] - pub fn file_name(&self) -> Option<&OsStr> { - self.components().next_back().and_then(|p| match p { - Component::Normal(p) => Some(p), - _ => None, - }) - } - - /// Returns a path that, when joined onto `base`, yields `self`. - /// - /// # Errors - /// - /// If `base` is not a prefix of `self` (i.e., [`starts_with`] - /// returns `false`), returns [`Err`]. - /// - /// [`starts_with`]: Path::starts_with - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("/test/haha/foo.txt"); - /// - /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt"))); - /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); - /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); - /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); - /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); - /// - /// assert!(path.strip_prefix("test").is_err()); - /// assert!(path.strip_prefix("/te").is_err()); - /// assert!(path.strip_prefix("/haha").is_err()); - /// - /// let prefix = PathBuf::from("/test/"); - /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); - /// ``` - #[stable(since = "1.7.0", feature = "path_strip_prefix")] - pub fn strip_prefix

(&self, base: P) -> Result<&Path, StripPrefixError> - where - P: AsRef, - { - self._strip_prefix(base.as_ref()) - } - - fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> { - iter_after(self.components(), base.components()) - .map(|c| c.as_path()) - .ok_or(StripPrefixError(())) - } - - /// Determines whether `base` is a prefix of `self`. - /// - /// Only considers whole path components to match. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/etc/passwd"); - /// - /// assert!(path.starts_with("/etc")); - /// assert!(path.starts_with("/etc/")); - /// assert!(path.starts_with("/etc/passwd")); - /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay - /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay - /// - /// assert!(!path.starts_with("/e")); - /// assert!(!path.starts_with("/etc/passwd.txt")); - /// - /// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn starts_with>(&self, base: P) -> bool { - self._starts_with(base.as_ref()) - } - - fn _starts_with(&self, base: &Path) -> bool { - iter_after(self.components(), base.components()).is_some() - } - - /// Determines whether `child` is a suffix of `self`. - /// - /// Only considers whole path components to match. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/etc/resolv.conf"); - /// - /// assert!(path.ends_with("resolv.conf")); - /// assert!(path.ends_with("etc/resolv.conf")); - /// assert!(path.ends_with("/etc/resolv.conf")); - /// - /// assert!(!path.ends_with("/resolv.conf")); - /// assert!(!path.ends_with("conf")); // use .extension() instead - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn ends_with>(&self, child: P) -> bool { - self._ends_with(child.as_ref()) - } - - fn _ends_with(&self, child: &Path) -> bool { - iter_after(self.components().rev(), child.components().rev()).is_some() - } - - /// Checks whether the `Path` is empty. - /// - /// # Examples - /// - /// ``` - /// #![feature(path_is_empty)] - /// use std::path::Path; - /// - /// let path = Path::new(""); - /// assert!(path.is_empty()); - /// - /// let path = Path::new("foo"); - /// assert!(!path.is_empty()); - /// - /// let path = Path::new("."); - /// assert!(!path.is_empty()); - /// ``` - #[unstable(feature = "path_is_empty", issue = "148494")] - pub fn is_empty(&self) -> bool { - self.as_os_str().is_empty() - } - - /// Extracts the stem (non-extension) portion of [`self.file_name`]. - /// - /// [`self.file_name`]: Path::file_name - /// - /// The stem is: - /// - /// * [`None`], if there is no file name; - /// * The entire file name if there is no embedded `.`; - /// * The entire file name if the file name begins with `.` and has no other `.`s within; - /// * Otherwise, the portion of the file name before the final `.` - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap()); - /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap()); - /// ``` - /// - /// # See Also - /// This method is similar to [`Path::file_prefix`], which extracts the portion of the file name - /// before the *first* `.` - /// - /// [`Path::file_prefix`]: Path::file_prefix - /// - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn file_stem(&self) -> Option<&OsStr> { - self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after)) - } - - /// Extracts the prefix of [`self.file_name`]. - /// - /// The prefix is: - /// - /// * [`None`], if there is no file name; - /// * The entire file name if there is no embedded `.`; - /// * The portion of the file name before the first non-beginning `.`; - /// * The entire file name if the file name begins with `.` and has no other `.`s within; - /// * The portion of the file name before the second `.` if the file name begins with `.` - /// - /// [`self.file_name`]: Path::file_name - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap()); - /// assert_eq!("foo", Path::new("foo.tar.gz").file_prefix().unwrap()); - /// assert_eq!(".config", Path::new(".config").file_prefix().unwrap()); - /// assert_eq!(".config", Path::new(".config.toml").file_prefix().unwrap()); - /// ``` - /// - /// # See Also - /// This method is similar to [`Path::file_stem`], which extracts the portion of the file name - /// before the *last* `.` - /// - /// [`Path::file_stem`]: Path::file_stem - /// - #[stable(feature = "path_file_prefix", since = "1.91.0")] - #[must_use] - pub fn file_prefix(&self) -> Option<&OsStr> { - self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before)) - } - - /// Extracts the extension (without the leading dot) of [`self.file_name`], if possible. - /// - /// The extension is: - /// - /// * [`None`], if there is no file name; - /// * [`None`], if there is no embedded `.`; - /// * [`None`], if the file name begins with `.` and has no other `.`s within; - /// * Otherwise, the portion of the file name after the final `.` - /// - /// [`self.file_name`]: Path::file_name - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// assert_eq!("rs", Path::new("foo.rs").extension().unwrap()); - /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn extension(&self) -> Option<&OsStr> { - self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after)) - } - - /// Checks whether the path ends in a trailing [separator](MAIN_SEPARATOR). - /// - /// This is generally done to ensure that a path is treated as a directory, not a file, - /// although it does not actually guarantee that such a path is a directory on the underlying - /// file system. - /// - /// Despite this behavior, two paths are still considered the same in Rust whether they have a - /// trailing separator or not. - /// - /// # Examples - /// - /// ``` - /// #![feature(path_trailing_sep)] - /// use std::path::Path; - /// - /// assert!(Path::new("dir/").has_trailing_sep()); - /// assert!(!Path::new("file.rs").has_trailing_sep()); - /// ``` - #[unstable(feature = "path_trailing_sep", issue = "142503")] - #[must_use] - #[inline] - pub fn has_trailing_sep(&self) -> bool { - self.as_os_str().as_encoded_bytes().last().copied().is_some_and(is_sep_byte) - } - - /// Ensures that a path has a trailing [separator](MAIN_SEPARATOR), - /// allocating a [`PathBuf`] if necessary. - /// - /// The resulting path will return true for [`has_trailing_sep`](Self::has_trailing_sep). - /// - /// # Examples - /// - /// ``` - /// #![feature(path_trailing_sep)] - /// use std::ffi::OsStr; - /// use std::path::Path; - /// - /// assert_eq!(Path::new("dir//").with_trailing_sep().as_os_str(), OsStr::new("dir//")); - /// assert_eq!(Path::new("dir/").with_trailing_sep().as_os_str(), OsStr::new("dir/")); - /// assert!(!Path::new("dir").has_trailing_sep()); - /// assert!(Path::new("dir").with_trailing_sep().has_trailing_sep()); - /// ``` - #[unstable(feature = "path_trailing_sep", issue = "142503")] - #[must_use] - #[inline] - pub fn with_trailing_sep(&self) -> Cow<'_, Path> { - if self.has_trailing_sep() { Cow::Borrowed(self) } else { Cow::Owned(self.join("")) } - } - - /// Trims a trailing [separator](MAIN_SEPARATOR) from a path, if possible. - /// - /// The resulting path will return false for [`has_trailing_sep`](Self::has_trailing_sep) for - /// most paths. - /// - /// Some paths, like `/`, cannot be trimmed in this way. - /// - /// # Examples - /// - /// ``` - /// #![feature(path_trailing_sep)] - /// use std::ffi::OsStr; - /// use std::path::Path; - /// - /// assert_eq!(Path::new("dir//").trim_trailing_sep().as_os_str(), OsStr::new("dir")); - /// assert_eq!(Path::new("dir/").trim_trailing_sep().as_os_str(), OsStr::new("dir")); - /// assert_eq!(Path::new("dir").trim_trailing_sep().as_os_str(), OsStr::new("dir")); - /// assert_eq!(Path::new("/").trim_trailing_sep().as_os_str(), OsStr::new("/")); - /// assert_eq!(Path::new("//").trim_trailing_sep().as_os_str(), OsStr::new("//")); - /// ``` - #[unstable(feature = "path_trailing_sep", issue = "142503")] - #[must_use] - #[inline] - pub fn trim_trailing_sep(&self) -> &Path { - if self.has_trailing_sep() && (!self.has_root() || self.parent().is_some()) { - let mut bytes = self.inner.as_encoded_bytes(); - while let Some((last, init)) = bytes.split_last() - && is_sep_byte(*last) - { - bytes = init; - } - - // SAFETY: Trimming trailing ASCII bytes will retain the validity of the string. - Path::new(unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }) - } else { - self - } - } - - /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. - /// - /// If `path` is absolute, it replaces the current path. - /// - /// On Windows: - /// - /// * if `path` has a root but no prefix (e.g., `\windows`), it - /// replaces and returns everything except for the prefix (if any) of `self`. - /// * if `path` has a prefix but no root, `self` is ignored and `path` is returned. - /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`) - /// and `path` is not empty, the new path is normalized: all references - /// to `.` and `..` are removed. - /// - /// See [`PathBuf::push`] for more details on what it means to adjoin a path. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); - /// assert_eq!(Path::new("/etc").join("/bin/sh"), PathBuf::from("/bin/sh")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn join>(&self, path: P) -> PathBuf { - self._join(path.as_ref()) - } - - fn _join(&self, path: &Path) -> PathBuf { - let mut buf = self.to_path_buf(); - buf.push(path); - buf - } - - /// Creates an owned [`PathBuf`] like `self` but with the given file name. - /// - /// See [`PathBuf::set_file_name`] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("/tmp/foo.png"); - /// assert_eq!(path.with_file_name("bar"), PathBuf::from("/tmp/bar")); - /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); - /// - /// let path = Path::new("/tmp"); - /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use] - pub fn with_file_name>(&self, file_name: S) -> PathBuf { - self._with_file_name(file_name.as_ref()) - } - - fn _with_file_name(&self, file_name: &OsStr) -> PathBuf { - let mut buf = self.to_path_buf(); - buf.set_file_name(file_name); - buf - } - - /// Creates an owned [`PathBuf`] like `self` but with the given extension. - /// - /// See [`PathBuf::set_extension`] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.rs"); - /// assert_eq!(path.with_extension("txt"), Path::new("foo.txt")); - /// assert_eq!(path.with_extension(""), Path::new("foo")); - /// ``` - /// - /// Handling multiple extensions: - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension("xz"), Path::new("foo.tar.xz")); - /// assert_eq!(path.with_extension("").with_extension("txt"), Path::new("foo.txt")); - /// ``` - /// - /// Adding an extension where one did not exist: - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("foo"); - /// assert_eq!(path.with_extension("rs"), Path::new("foo.rs")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_extension>(&self, extension: S) -> PathBuf { - self._with_extension(extension.as_ref()) - } - - fn _with_extension(&self, extension: &OsStr) -> PathBuf { - let self_len = self.as_os_str().len(); - let self_bytes = self.as_os_str().as_encoded_bytes(); - - let (new_capacity, slice_to_copy) = match self.extension() { - None => { - // Enough capacity for the extension and the dot - let capacity = self_len + extension.len() + 1; - let whole_path = self_bytes; - (capacity, whole_path) - } - Some(previous_extension) => { - let capacity = self_len + extension.len() - previous_extension.len(); - let path_till_dot = &self_bytes[..self_len - previous_extension.len()]; - (capacity, path_till_dot) - } - }; - - let mut new_path = PathBuf::with_capacity(new_capacity); - // SAFETY: The path is empty, so cannot have surrogate halves. - unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) }; - new_path.set_extension(extension); - new_path - } - - /// Creates an owned [`PathBuf`] like `self` but with the extension added. - /// - /// See [`PathBuf::add_extension`] for more details. - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("foo.rs"); - /// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt")); - /// - /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz")); - /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz")); - /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt")); - /// ``` - #[stable(feature = "path_add_extension", since = "1.91.0")] - pub fn with_added_extension>(&self, extension: S) -> PathBuf { - let mut new_path = self.to_path_buf(); - new_path.add_extension(extension); - new_path - } - - /// Produces an iterator over the [`Component`]s of the path. - /// - /// When parsing the path, there is a small amount of normalization: - /// - /// * Repeated separators are ignored, so `a/b` and `a//b` both have - /// `a` and `b` as components. - /// - /// * Occurrences of `.` are normalized away, except if they are at the - /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and - /// `a/b` all have `a` and `b` as components, but `./a/b` starts with - /// an additional [`CurDir`] component. - /// - /// * Trailing separators are normalized away, so `/a/b` and `/a/b/` are equivalent. - /// - /// Note that no other normalization takes place; in particular, `a/c` - /// and `a/b/../c` are distinct, to account for the possibility that `b` - /// is a symbolic link (so its parent isn't `a`). - /// - /// # Examples - /// - /// ``` - /// use std::path::{Path, Component}; - /// use std::ffi::OsStr; - /// - /// let mut components = Path::new("/tmp/foo.txt").components(); - /// - /// assert_eq!(components.next(), Some(Component::RootDir)); - /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp")))); - /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt")))); - /// assert_eq!(components.next(), None) - /// ``` - /// - /// [`CurDir`]: Component::CurDir - #[stable(feature = "rust1", since = "1.0.0")] - pub fn components(&self) -> Components<'_> { - let prefix = parse_prefix(self.as_os_str()); - Components { - path: self.as_u8_slice(), - prefix, - has_physical_root: has_physical_root(self.as_u8_slice(), prefix), - // use a platform-specific initial state to avoid one turn of - // the state-machine when the platform doesn't have a Prefix. - front: const { if HAS_PREFIXES { State::Prefix } else { State::StartDir } }, - back: State::Body, - } - } - - /// Produces an iterator over the path's components viewed as [`OsStr`] - /// slices. - /// - /// For more information about the particulars of how the path is separated - /// into components, see [`components`]. - /// - /// [`components`]: Path::components - /// - /// # Examples - /// - /// ``` - /// use std::path::{self, Path}; - /// use std::ffi::OsStr; - /// - /// let mut it = Path::new("/tmp/foo.txt").iter(); - /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string()))); - /// assert_eq!(it.next(), Some(OsStr::new("tmp"))); - /// assert_eq!(it.next(), Some(OsStr::new("foo.txt"))); - /// assert_eq!(it.next(), None) - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn iter(&self) -> Iter<'_> { - Iter { inner: self.components() } - } - - /// Returns an object that implements [`Display`] for safely printing paths - /// that may contain non-Unicode data. This may perform lossy conversion, - /// depending on the platform. If you would like an implementation which - /// escapes the path please use [`Debug`] instead. - /// - /// [`Display`]: fmt::Display - /// [`Debug`]: fmt::Debug - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// - /// let path = Path::new("/tmp/foo.rs"); - /// - /// println!("{}", path.display()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this does not display the path, \ - it returns an object that can be displayed"] - #[inline] - pub fn display(&self) -> Display<'_> { - Display { inner: self.inner.display() } - } - - /// Returns the same path as `&Path`. - /// - /// This method is redundant when used directly on `&Path`, but - /// it helps dereferencing other `PathBuf`-like types to `Path`s, - /// for example references to `Box` or `Arc`. - #[inline] - #[unstable(feature = "str_as_str", issue = "130366")] - pub const fn as_path(&self) -> &Path { - self - } - - /// Queries the file system to get information about a file, directory, etc. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. - /// - /// This is an alias to [`fs::metadata`]. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/Minas/tirith"); - /// let metadata = path.metadata().expect("metadata call failed"); - /// println!("{:?}", metadata.file_type()); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] - pub fn metadata(&self) -> io::Result { - fs::metadata(self) - } - - /// Queries the metadata about a file without following symlinks. - /// - /// This is an alias to [`fs::symlink_metadata`]. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/Minas/tirith"); - /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed"); - /// println!("{:?}", metadata.file_type()); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] - pub fn symlink_metadata(&self) -> io::Result { - fs::symlink_metadata(self) - } - - /// Returns the canonical, absolute form of the path with all intermediate - /// components normalized and symbolic links resolved. - /// - /// This is an alias to [`fs::canonicalize`]. - /// - /// # Errors - /// - /// This method will return an error in the following situations, but is not - /// limited to just these cases: - /// - /// * `path` does not exist. - /// * A non-final component in path is not a directory. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::{Path, PathBuf}; - /// - /// let path = Path::new("/foo/test/../test/bar.rs"); - /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] - pub fn canonicalize(&self) -> io::Result { - fs::canonicalize(self) - } - - /// Makes the path absolute without accessing the filesystem. - /// - /// This is an alias to [`path::absolute`](absolute). - /// - /// # Errors - /// - /// This function may return an error in the following situations: - /// - /// * If the path is syntactically invalid; in particular, if it is empty. - /// * If getting the [current directory][crate::env::current_dir] fails. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(path_absolute_method)] - /// use std::path::Path; - /// - /// let path = Path::new("foo/./bar"); - /// let absolute = path.absolute()?; - /// assert!(absolute.is_absolute()); - /// # Ok::<(), std::io::Error>(()) - /// ``` - #[unstable(feature = "path_absolute_method", issue = "153328")] - #[inline] - pub fn absolute(&self) -> io::Result { - absolute(self) - } - - /// Normalize a path, including `..` without traversing the filesystem. - /// - /// Returns an error if normalization would leave leading `..` components. - /// - ///

- /// - /// This function always resolves `..` to the "lexical" parent. - /// That is "a/b/../c" will always resolve to `a/c` which can change the meaning of the path. - /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn't `a`. - /// - ///
- /// - /// [`path::absolute`](absolute) is an alternative that preserves `..`. - /// Or [`Path::canonicalize`] can be used to resolve any `..` by querying the filesystem. - #[unstable(feature = "normalize_lexically", issue = "134694")] - pub fn normalize_lexically(&self) -> Result { - let mut lexical = PathBuf::new(); - let mut iter = self.components().peekable(); - - // Find the root, if any, and add it to the lexical path. - // Here we treat the Windows path "C:\" as a single "root" even though - // `components` splits it into two: (Prefix, RootDir). - let root = match iter.peek() { - Some(Component::ParentDir) => return Err(NormalizeError), - Some(p @ Component::RootDir) | Some(p @ Component::CurDir) => { - lexical.push(p); - iter.next(); - lexical.as_os_str().len() - } - Some(Component::Prefix(prefix)) => { - lexical.push(prefix.as_os_str()); - iter.next(); - if let Some(p @ Component::RootDir) = iter.peek() { - lexical.push(p); - iter.next(); - } - lexical.as_os_str().len() - } - None => return Ok(PathBuf::new()), - Some(Component::Normal(_)) => 0, - }; - - for component in iter { - match component { - Component::RootDir => unreachable!(), - Component::Prefix(_) => return Err(NormalizeError), - Component::CurDir => continue, - Component::ParentDir => { - // It's an error if ParentDir causes us to go above the "root". - if lexical.as_os_str().len() == root { - return Err(NormalizeError); - } else { - lexical.pop(); - } - } - Component::Normal(path) => lexical.push(path), - } - } - Ok(lexical) - } - - /// Reads a symbolic link, returning the file that the link points to. - /// - /// This is an alias to [`fs::read_link`]. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/laputa/sky_castle.rs"); - /// let path_link = path.read_link().expect("read_link call failed"); - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] - pub fn read_link(&self) -> io::Result { - fs::read_link(self) - } - - /// Returns an iterator over the entries within a directory. - /// - /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New - /// errors may be encountered after an iterator is initially constructed. - /// - /// This is an alias to [`fs::read_dir`]. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// - /// let path = Path::new("/laputa"); - /// for entry in path.read_dir().expect("read_dir call failed") { - /// if let Ok(entry) = entry { - /// println!("{:?}", entry.path()); - /// } - /// } - /// ``` - #[stable(feature = "path_ext", since = "1.5.0")] - #[inline] - pub fn read_dir(&self) -> io::Result { - fs::read_dir(self) - } - - /// Returns `true` if the path points at an existing entity. - /// - /// Warning: this method may be error-prone, consider using [`try_exists()`] instead! - /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. - /// - /// If you cannot access the metadata of the file, e.g. because of a - /// permission error or broken symbolic links, this will return `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// assert!(!Path::new("does_not_exist.txt").exists()); - /// ``` - /// - /// # See Also - /// - /// This is a convenience function that coerces errors to false. If you want to - /// check errors, call [`Path::try_exists`]. - /// - /// [`try_exists()`]: Self::try_exists - /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou - #[stable(feature = "path_ext", since = "1.5.0")] - #[must_use] - #[inline] - pub fn exists(&self) -> bool { - fs::metadata(self).is_ok() - } - - /// Returns `Ok(true)` if the path points at an existing entity. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. In case of broken symbolic links this will return `Ok(false)`. - /// - /// [`Path::exists()`] only checks whether or not a path was both found and readable. By - /// contrast, `try_exists` will return `Ok(true)` or `Ok(false)`, respectively, if the path - /// was _verified_ to exist or not exist. If its existence can neither be confirmed nor - /// denied, it will propagate an `Err(_)` instead. This can be the case if e.g. listing - /// permission is denied on one of the parent directories. - /// - /// Note that while this avoids some pitfalls of the `exists()` method, it still can not - /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios - /// where those bugs are not an issue. - /// - /// This is an alias for [`std::fs::exists`](crate::fs::exists). - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt")); - /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err()); - /// ``` - /// - /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou - /// [`exists()`]: Self::exists - #[stable(feature = "path_try_exists", since = "1.63.0")] - #[inline] - pub fn try_exists(&self) -> io::Result { - fs::exists(self) - } - - /// Returns `true` if the path exists on disk and is pointing at a regular file. - /// - /// This function will traverse symbolic links to query information about the - /// destination file. - /// - /// If you cannot access the metadata of the file, e.g. because of a - /// permission error or broken symbolic links, this will return `false`. - /// - /// # Examples - /// - /// ```no_run - /// use std::path::Path; - /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); - /// assert_eq!(Path::new("a_file.txt").is_file(), true); - /// ``` - /// - /// # See Also - /// - /// This is a convenience function that coerces errors to false. If you want to - /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call - /// [`fs::Metadata::is_file`] if it was [`Ok`]. - /// - /// When the goal is simply to read from (or write to) the source, the most - /// reliable way to test the source can be read (or written to) is to open - /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on - /// a Unix-like system for example. See [`fs::File::open`] or - /// [`fs::OpenOptions::open`] for more information. - #[stable(feature = "path_ext", since = "1.5.0")] - #[must_use] - pub fn is_file(&self) -> bool { - fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) - } - - /// Returns `true` if the path exists on disk and is pointing at a 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) - } - - /// Converts a [`Box`](Box) into a [`PathBuf`] without copying or - /// allocating. - #[stable(feature = "into_boxed_path", since = "1.20.0")] - #[must_use = "`self` will be dropped if the result is not used"] - pub fn into_path_buf(self: Box) -> PathBuf { - let rw = Box::into_raw(self) as *mut OsStr; - let inner = unsafe { Box::from_raw(rw) }; - PathBuf { inner: OsString::from(inner) } - } -} - -#[unstable(feature = "clone_to_uninit", issue = "126799")] -unsafe impl CloneToUninit for Path { - #[inline] - #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { - // SAFETY: Path is just a transparent wrapper around OsStr - unsafe { self.inner.clone_to_uninit(dst) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const AsRef for Path { - #[inline] - fn as_ref(&self) -> &OsStr { - &self.inner - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Path { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.inner, formatter) - } -} - -/// Helper struct for safely printing paths with [`format!`] and `{}`. -/// -/// A [`Path`] might contain non-Unicode data. This `struct` implements the -/// [`Display`] trait in a way that mitigates that. It is created by the -/// [`display`](Path::display) method on [`Path`]. This may perform lossy -/// conversion, depending on the platform. If you would like an implementation -/// which escapes the path please use [`Debug`] instead. -/// -/// # Examples -/// -/// ``` -/// use std::path::Path; -/// -/// let path = Path::new("/tmp/foo.rs"); -/// -/// println!("{}", path.display()); -/// ``` -/// -/// [`Display`]: fmt::Display -/// [`format!`]: crate::format -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Display<'a> { - inner: os_str::Display<'a>, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Display<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.inner, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Display<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.inner, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { - self.components() == other.components() - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for Path { - #[inline] - fn eq(&self, other: &str) -> bool { - let other: &OsStr = other.as_ref(); - self == other - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for str { - #[inline] - fn eq(&self, other: &Path) -> bool { - other == self - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for Path { - #[inline] - fn eq(&self, other: &String) -> bool { - self == other.as_str() - } -} - -#[stable(feature = "eq_str_for_path", since = "1.91.0")] -impl cmp::PartialEq for String { - #[inline] - fn eq(&self, other: &Path) -> bool { - self.as_str() == other - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Path { - fn hash(&self, h: &mut H) { - let bytes = self.as_u8_slice(); - let (prefix_len, verbatim) = match parse_prefix(&self.inner) { - Some(prefix) => { - prefix.hash(h); - (prefix.len(), prefix.is_verbatim()) - } - None => (0, false), - }; - let bytes = &bytes[prefix_len..]; - - let mut component_start = 0; - // track some extra state to avoid prefix collisions. - // ["foo", "bar"] and ["foobar"], will have the same payload bytes - // but result in different chunk_bits - let mut chunk_bits: usize = 0; - - for i in 0..bytes.len() { - let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) }; - if is_sep { - if i > component_start { - let to_hash = &bytes[component_start..i]; - chunk_bits = chunk_bits.wrapping_add(to_hash.len()); - chunk_bits = chunk_bits.rotate_right(2); - h.write(to_hash); - } - - // skip over separator and optionally a following CurDir item - // since components() would normalize these away. - component_start = i + 1; - - let tail = &bytes[component_start..]; - - if !verbatim { - component_start += match tail { - [b'.'] => 1, - [b'.', sep, ..] if is_sep_byte(*sep) => 1, - _ => 0, - }; - } - } - } - - if component_start < bytes.len() { - let to_hash = &bytes[component_start..]; - chunk_bits = chunk_bits.wrapping_add(to_hash.len()); - chunk_bits = chunk_bits.rotate_right(2); - h.write(to_hash); - } - - h.write_usize(chunk_bits); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Path {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Path { - #[inline] - fn partial_cmp(&self, other: &Path) -> Option { - Some(compare_components(self.components(), other.components())) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Path { - #[inline] - fn cmp(&self, other: &Path) -> cmp::Ordering { - compare_components(self.components(), other.components()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const AsRef for Path { - #[inline] - fn as_ref(&self) -> &Path { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const AsRef for OsStr { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")] -impl AsRef for Cow<'_, OsStr> { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for OsString { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for str { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for String { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRef for PathBuf { - #[inline] - fn as_ref(&self) -> &Path { - self - } -} - -#[stable(feature = "path_into_iter", since = "1.6.0")] -impl<'a> IntoIterator for &'a PathBuf { - type Item = &'a OsStr; - type IntoIter = Iter<'a>; - #[inline] - fn into_iter(self) -> Iter<'a> { - self.iter() - } -} - -#[stable(feature = "path_into_iter", since = "1.6.0")] -impl<'a> IntoIterator for &'a Path { - type Item = &'a OsStr; - type IntoIter = Iter<'a>; - #[inline] - fn into_iter(self) -> Iter<'a> { - self.iter() - } -} - -macro_rules! impl_cmp { - ($lhs:ty, $rhs: ty) => { - #[stable(feature = "partialeq_path", since = "1.6.0")] - impl PartialEq<$rhs> for $lhs { - #[inline] - fn eq(&self, other: &$rhs) -> bool { - ::eq(self, other) - } - } - - #[stable(feature = "partialeq_path", since = "1.6.0")] - impl PartialEq<$lhs> for $rhs { - #[inline] - fn eq(&self, other: &$lhs) -> bool { - ::eq(self, other) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl PartialOrd<$rhs> for $lhs { - #[inline] - fn partial_cmp(&self, other: &$rhs) -> Option { - ::partial_cmp(self, other) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl PartialOrd<$lhs> for $rhs { - #[inline] - fn partial_cmp(&self, other: &$lhs) -> Option { - ::partial_cmp(self, other) - } - } - }; -} - -impl_cmp!(PathBuf, Path); -impl_cmp!(PathBuf, &Path); -impl_cmp!(Cow<'_, Path>, Path); -impl_cmp!(Cow<'_, Path>, &Path); -impl_cmp!(Cow<'_, Path>, PathBuf); - -macro_rules! impl_cmp_os_str { - ($lhs:ty, $rhs: ty) => { - #[stable(feature = "cmp_path", since = "1.8.0")] - impl PartialEq<$rhs> for $lhs { - #[inline] - fn eq(&self, other: &$rhs) -> bool { - ::eq(self, other.as_ref()) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl PartialEq<$lhs> for $rhs { - #[inline] - fn eq(&self, other: &$lhs) -> bool { - ::eq(self.as_ref(), other) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl PartialOrd<$rhs> for $lhs { - #[inline] - fn partial_cmp(&self, other: &$rhs) -> Option { - ::partial_cmp(self, other.as_ref()) - } - } - - #[stable(feature = "cmp_path", since = "1.8.0")] - impl PartialOrd<$lhs> for $rhs { - #[inline] - fn partial_cmp(&self, other: &$lhs) -> Option { - ::partial_cmp(self.as_ref(), other) - } - } - }; -} - -impl_cmp_os_str!(PathBuf, OsStr); -impl_cmp_os_str!(PathBuf, &OsStr); -impl_cmp_os_str!(PathBuf, Cow<'_, OsStr>); -impl_cmp_os_str!(PathBuf, OsString); -impl_cmp_os_str!(Path, OsStr); -impl_cmp_os_str!(Path, &OsStr); -impl_cmp_os_str!(Path, Cow<'_, OsStr>); -impl_cmp_os_str!(Path, OsString); -impl_cmp_os_str!(&Path, OsStr); -impl_cmp_os_str!(&Path, Cow<'_, OsStr>); -impl_cmp_os_str!(&Path, OsString); -impl_cmp_os_str!(Cow<'_, Path>, OsStr); -impl_cmp_os_str!(Cow<'_, Path>, &OsStr); -impl_cmp_os_str!(Cow<'_, Path>, OsString); - -#[stable(since = "1.7.0", feature = "strip_prefix")] -impl fmt::Display for StripPrefixError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "prefix not found".fmt(f) - } -} - -#[stable(since = "1.7.0", feature = "strip_prefix")] -impl Error for StripPrefixError {} - -#[unstable(feature = "normalize_lexically", issue = "134694")] -impl fmt::Display for NormalizeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("parent reference `..` points outside of base directory") - } -} -#[unstable(feature = "normalize_lexically", issue = "134694")] -impl Error for NormalizeError {} - -/// Makes the path absolute without accessing the filesystem. -/// -/// If the path is relative, the current directory is used as the base directory. -/// All intermediate components will be resolved according to platform-specific -/// rules, but unlike [`canonicalize`][crate::fs::canonicalize], this does not -/// resolve symlinks and may succeed even if the path does not exist. -/// -/// If the `path` is empty or getting the -/// [current directory][crate::env::current_dir] fails, then an error will be -/// returned. -/// -/// # Platform-specific behavior -/// -/// On POSIX platforms, the path is resolved using [POSIX semantics][posix-semantics], -/// except that it stops short of resolving symlinks. This means it will keep `..` -/// components and trailing separators. -/// -/// On Windows, for verbatim paths, this will simply return the path as given. For other -/// paths, this is currently equivalent to calling -/// [`GetFullPathNameW`][windows-path]. -/// -/// On Cygwin, this is currently equivalent to calling [`cygwin_conv_path`][cygwin-path] -/// with mode `CCP_WIN_A_TO_POSIX`, and then being processed like other POSIX platforms. -/// If a Windows path is given, it will be converted to an absolute POSIX path without -/// keeping `..`. -/// -/// Note that these [may change in the future][changes]. -/// -/// # Errors -/// -/// This function may return an error in the following situations: -/// -/// * If `path` is syntactically invalid; in particular, if it is empty. -/// * If getting the [current directory][crate::env::current_dir] fails. -/// -/// # Examples -/// -/// ## POSIX paths -/// -/// ``` -/// # #[cfg(unix)] -/// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; -/// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with("foo/bar")); -/// -/// // Absolute to absolute -/// let absolute = path::absolute("/foo//test/.././bar.rs")?; -/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); -/// Ok(()) -/// } -/// # #[cfg(not(unix))] -/// # fn main() {} -/// ``` -/// -/// ## Windows paths -/// -/// ``` -/// # #[cfg(windows)] -/// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; -/// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with(r"foo\bar")); -/// -/// // Absolute to absolute -/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; -/// -/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); -/// Ok(()) -/// } -/// # #[cfg(not(windows))] -/// # fn main() {} -/// ``` -/// -/// Note that this [may change in the future][changes]. -/// -/// [changes]: io#platform-specific-behavior -/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 -/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew -/// [cygwin-path]: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html -#[stable(feature = "absolute_path", since = "1.79.0")] -pub fn absolute>(path: P) -> io::Result { - let path = path.as_ref(); - if path.as_os_str().is_empty() { - Err(io::const_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute")) - } else { - sys::path::absolute(path) - } -} diff --git a/library/std/src/path.rs b/library/std/src/path.rs new file mode 120000 index 0000000..f620d82 --- /dev/null +++ b/library/std/src/path.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/path.rs \ No newline at end of file diff --git a/library/std/src/process.rs b/library/std/src/process.rs deleted file mode 100644 index 321b68b..0000000 --- a/library/std/src/process.rs +++ /dev/null @@ -1,2622 +0,0 @@ -//! A module for working with processes. -//! -//! This module is mostly concerned with spawning and interacting with child -//! processes, but it also provides [`abort`] and [`exit`] for terminating the -//! current process. -//! -//! # Spawning a process -//! -//! The [`Command`] struct is used to configure and spawn processes: -//! -//! ```no_run -//! use std::process::Command; -//! -//! let output = Command::new("echo") -//! .arg("Hello world") -//! .output() -//! .expect("Failed to execute command"); -//! -//! assert_eq!(b"Hello world\n", output.stdout.as_slice()); -//! ``` -//! -//! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used -//! to spawn a process. In particular, [`output`] spawns the child process and -//! waits until the process terminates, while [`spawn`] will return a [`Child`] -//! that represents the spawned child process. -//! -//! # Handling I/O -//! -//! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be -//! configured by passing an [`Stdio`] to the corresponding method on -//! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For -//! example, piping output from one command into another command can be done -//! like so: -//! -//! ```no_run -//! use std::process::{Command, Stdio}; -//! -//! // stdout must be configured with `Stdio::piped` in order to use -//! // `echo_child.stdout` -//! let echo_child = Command::new("echo") -//! .arg("Oh no, a tpyo!") -//! .stdout(Stdio::piped()) -//! .spawn() -//! .expect("Failed to start echo process"); -//! -//! // Note that `echo_child` is moved here, but we won't be needing -//! // `echo_child` anymore -//! let echo_out = echo_child.stdout.expect("Failed to open echo stdout"); -//! -//! let mut sed_child = Command::new("sed") -//! .arg("s/tpyo/typo/") -//! .stdin(Stdio::from(echo_out)) -//! .stdout(Stdio::piped()) -//! .spawn() -//! .expect("Failed to start sed process"); -//! -//! let output = sed_child.wait_with_output().expect("Failed to wait on sed"); -//! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice()); -//! ``` -//! -//! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Read`] and -//! [`ChildStdin`] implements [`Write`]: -//! -//! ```no_run -//! use std::process::{Command, Stdio}; -//! use std::io::Write; -//! -//! let mut child = Command::new("/bin/cat") -//! .stdin(Stdio::piped()) -//! .stdout(Stdio::piped()) -//! .spawn() -//! .expect("failed to execute child"); -//! -//! // If the child process fills its stdout buffer, it may end up -//! // waiting until the parent reads the stdout, and not be able to -//! // read stdin in the meantime, causing a deadlock. -//! // Writing from another thread ensures that stdout is being read -//! // at the same time, avoiding the problem. -//! let mut stdin = child.stdin.take().expect("failed to get stdin"); -//! std::thread::spawn(move || { -//! stdin.write_all(b"test").expect("failed to write to stdin"); -//! }); -//! -//! let output = child -//! .wait_with_output() -//! .expect("failed to wait on child"); -//! -//! assert_eq!(b"test", output.stdout.as_slice()); -//! ``` -//! -//! # Windows argument splitting -//! -//! On Unix systems arguments are passed to a new process as an array of strings, -//! but on Windows arguments are passed as a single commandline string and it is -//! up to the child process to parse it into an array. Therefore the parent and -//! child processes must agree on how the commandline string is encoded. -//! -//! Most programs use the standard C run-time `argv`, which in practice results -//! in consistent argument handling. However, some programs have their own way of -//! parsing the commandline string. In these cases using [`arg`] or [`args`] may -//! result in the child process seeing a different array of arguments than the -//! parent process intended. -//! -//! Two ways of mitigating this are: -//! -//! * Validate untrusted input so that only a safe subset is allowed. -//! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping -//! rules used by [`arg`] so should be used with due caution. -//! -//! `cmd.exe` and `.bat` files use non-standard argument parsing and are especially -//! vulnerable to malicious input as they may be used to run arbitrary shell -//! commands. Untrusted arguments should be restricted as much as possible. -//! For examples on handling this see [`raw_arg`]. -//! -//! ### Batch file special handling -//! -//! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to -//! spawn new processes. An undocumented feature of this function is that -//! when given a `.bat` file as the application to run, it will automatically -//! convert that into running `cmd.exe /c` with the batch file as the next argument. -//! -//! For historical reasons Rust currently preserves this behavior when using -//! [`Command::new`], and escapes the arguments according to `cmd.exe` rules. -//! Due to the complexity of `cmd.exe` argument handling, it might not be -//! possible to safely escape some special characters, and using them will result -//! in an error being returned at process spawn. The set of unescapeable -//! special characters might change between releases. -//! -//! Also note that running batch scripts in this way may be removed in the -//! future and so should not be relied upon. -//! -//! [`spawn`]: Command::spawn -//! [`output`]: Command::output -//! -//! [`stdout`]: Command::stdout -//! [`stdin`]: Command::stdin -//! [`stderr`]: Command::stderr -//! -//! [`Write`]: io::Write -//! [`Read`]: io::Read -//! -//! [`arg`]: Command::arg -//! [`args`]: Command::args -//! [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg -//! -//! [`CreateProcessW`]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw - -#![stable(feature = "process", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] - -#[cfg(all( - test, - not(any( - target_os = "emscripten", - target_os = "wasi", - target_env = "sgx", - target_os = "xous", - target_os = "trusty", - target_os = "hermit", - )) -))] -mod tests; - -use crate::convert::Infallible; -use crate::ffi::OsStr; -use crate::io::prelude::*; -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::num::NonZero; -use crate::path::Path; -use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, process as imp}; -use crate::{fmt, format_args_nl, fs, str}; - -/// Representation of a running or exited child process. -/// -/// This structure is used to represent and manage child processes. A child -/// process is created via the [`Command`] struct, which configures the -/// spawning process and can itself be constructed using a builder-style -/// interface. -/// -/// There is no implementation of [`Drop`] for child processes, -/// so if you do not ensure the `Child` has exited then it will continue to -/// run, even after the `Child` handle to the child process has gone out of -/// scope. -/// -/// Calling [`wait`] (or other functions that wrap around it) will make -/// the parent process wait until the child has actually exited before -/// continuing. -/// -/// # Warning -/// -/// On some systems, calling [`wait`] or similar is necessary for the OS to -/// release resources. A process that terminated but has not been waited on is -/// still around as a "zombie". Leaving too many zombies around may exhaust -/// global resources (for example process IDs). -/// -/// The standard library does *not* automatically wait on child processes (not -/// even if the `Child` is dropped), it is up to the application developer to do -/// so. As a consequence, dropping `Child` handles without waiting on them first -/// is not recommended in long-running applications. -/// -/// # Examples -/// -/// ```should_panic -/// use std::process::Command; -/// -/// let mut child = Command::new("/bin/cat") -/// .arg("file.txt") -/// .spawn() -/// .expect("failed to execute child"); -/// -/// let ecode = child.wait().expect("failed to wait on child"); -/// -/// assert!(ecode.success()); -/// ``` -/// -/// [`wait`]: Child::wait -#[stable(feature = "process", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Child")] -pub struct Child { - pub(crate) handle: imp::Process, - - /// The handle for writing to the child's standard input (stdin), if it - /// has been captured. You might find it helpful to do - /// - /// ```ignore (incomplete) - /// let stdin = child.stdin.take().expect("handle present"); - /// ``` - /// - /// to avoid partially moving the `child` and thus blocking yourself from calling - /// functions on `child` while using `stdin`. - #[stable(feature = "process", since = "1.0.0")] - pub stdin: Option, - - /// The handle for reading from the child's standard output (stdout), if it - /// has been captured. You might find it helpful to do - /// - /// ```ignore (incomplete) - /// let stdout = child.stdout.take().expect("handle present"); - /// ``` - /// - /// to avoid partially moving the `child` and thus blocking yourself from calling - /// functions on `child` while using `stdout`. - #[stable(feature = "process", since = "1.0.0")] - pub stdout: Option, - - /// The handle for reading from the child's standard error (stderr), if it - /// has been captured. You might find it helpful to do - /// - /// ```ignore (incomplete) - /// let stderr = child.stderr.take().expect("handle present"); - /// ``` - /// - /// to avoid partially moving the `child` and thus blocking yourself from calling - /// functions on `child` while using `stderr`. - #[stable(feature = "process", since = "1.0.0")] - pub stderr: Option, -} - -/// Allows extension traits within `std`. -#[unstable(feature = "sealed", issue = "none")] -impl crate::sealed::Sealed for Child {} - -impl AsInner for Child { - #[inline] - fn as_inner(&self) -> &imp::Process { - &self.handle - } -} - -impl FromInner<(imp::Process, StdioPipes)> for Child { - fn from_inner((handle, io): (imp::Process, StdioPipes)) -> Child { - Child { - handle, - stdin: io.stdin.map(ChildStdin::from_inner), - stdout: io.stdout.map(ChildStdout::from_inner), - stderr: io.stderr.map(ChildStderr::from_inner), - } - } -} - -impl IntoInner for Child { - fn into_inner(self) -> imp::Process { - self.handle - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Child { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Child") - .field("stdin", &self.stdin) - .field("stdout", &self.stdout) - .field("stderr", &self.stderr) - .finish_non_exhaustive() - } -} - -/// The pipes connected to a spawned process. -/// -/// Used to pass pipe handles between this module and [`imp`]. -pub(crate) struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -/// A handle to a child process's standard input (stdin). -/// -/// This struct is used in the [`stdin`] field on [`Child`]. -/// -/// When an instance of `ChildStdin` is [dropped], the `ChildStdin`'s underlying -/// file handle will be closed. If the child process was blocked on input prior -/// to being dropped, it will become unblocked after dropping. -/// -/// [`stdin`]: Child::stdin -/// [dropped]: Drop -#[stable(feature = "process", since = "1.0.0")] -pub struct ChildStdin { - inner: imp::ChildPipe, -} - -// In addition to the `impl`s here, `ChildStdin` also has `impl`s for -// `AsFd`/`From`/`Into` and -// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and -// `AsHandle`/`From`/`Into` and -// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. - -#[stable(feature = "process", since = "1.0.0")] -impl Write for ChildStdin { - fn write(&mut self, buf: &[u8]) -> io::Result { - (&*self).write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - (&*self).write_vectored(bufs) - } - - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - (&*self).flush() - } -} - -#[stable(feature = "write_mt", since = "1.48.0")] -impl Write for &ChildStdin { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.inner.write_vectored(bufs) - } - - fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl AsInner for ChildStdin { - #[inline] - fn as_inner(&self) -> &imp::ChildPipe { - &self.inner - } -} - -impl IntoInner for ChildStdin { - fn into_inner(self) -> imp::ChildPipe { - self.inner - } -} - -impl FromInner for ChildStdin { - fn from_inner(pipe: imp::ChildPipe) -> ChildStdin { - ChildStdin { inner: pipe } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ChildStdin { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ChildStdin").finish_non_exhaustive() - } -} - -/// A handle to a child process's standard output (stdout). -/// -/// This struct is used in the [`stdout`] field on [`Child`]. -/// -/// When an instance of `ChildStdout` is [dropped], the `ChildStdout`'s -/// underlying file handle will be closed. -/// -/// [`stdout`]: Child::stdout -/// [dropped]: Drop -#[stable(feature = "process", since = "1.0.0")] -pub struct ChildStdout { - inner: imp::ChildPipe, -} - -// In addition to the `impl`s here, `ChildStdout` also has `impl`s for -// `AsFd`/`From`/`Into` and -// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and -// `AsHandle`/`From`/`Into` and -// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. - -#[stable(feature = "process", since = "1.0.0")] -impl Read for ChildStdout { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.inner.read_buf(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.inner.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) - } -} - -impl AsInner for ChildStdout { - #[inline] - fn as_inner(&self) -> &imp::ChildPipe { - &self.inner - } -} - -impl IntoInner for ChildStdout { - fn into_inner(self) -> imp::ChildPipe { - self.inner - } -} - -impl FromInner for ChildStdout { - fn from_inner(pipe: imp::ChildPipe) -> ChildStdout { - ChildStdout { inner: pipe } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ChildStdout { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ChildStdout").finish_non_exhaustive() - } -} - -/// A handle to a child process's stderr. -/// -/// This struct is used in the [`stderr`] field on [`Child`]. -/// -/// When an instance of `ChildStderr` is [dropped], the `ChildStderr`'s -/// underlying file handle will be closed. -/// -/// [`stderr`]: Child::stderr -/// [dropped]: Drop -#[stable(feature = "process", since = "1.0.0")] -pub struct ChildStderr { - inner: imp::ChildPipe, -} - -// In addition to the `impl`s here, `ChildStderr` also has `impl`s for -// `AsFd`/`From`/`Into` and -// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and -// `AsHandle`/`From`/`Into` and -// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. - -#[stable(feature = "process", since = "1.0.0")] -impl Read for ChildStderr { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } - - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.inner.read_buf(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.inner.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.inner.read_to_end(buf) - } -} - -impl AsInner for ChildStderr { - #[inline] - fn as_inner(&self) -> &imp::ChildPipe { - &self.inner - } -} - -impl IntoInner for ChildStderr { - fn into_inner(self) -> imp::ChildPipe { - self.inner - } -} - -impl FromInner for ChildStderr { - fn from_inner(pipe: imp::ChildPipe) -> ChildStderr { - ChildStderr { inner: pipe } - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ChildStderr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ChildStderr").finish_non_exhaustive() - } -} - -/// A process builder, providing fine-grained control -/// over how a new process should be spawned. -/// -/// A default configuration can be -/// generated using `Command::new(program)`, where `program` gives a path to the -/// program to be executed. Additional builder methods allow the configuration -/// to be changed (for example, by adding arguments) prior to spawning: -/// -/// ``` -/// # if cfg!(not(all(target_vendor = "apple", not(target_os = "macos")))) { -/// use std::process::Command; -/// -/// let output = if cfg!(target_os = "windows") { -/// Command::new("cmd") -/// .args(["/C", "echo hello"]) -/// .output() -/// .expect("failed to execute process") -/// } else { -/// Command::new("sh") -/// .arg("-c") -/// .arg("echo hello") -/// .output() -/// .expect("failed to execute process") -/// }; -/// -/// let hello = output.stdout; -/// # } -/// ``` -/// -/// `Command` can be reused to spawn multiple processes. The builder methods -/// change the command without needing to immediately spawn the process. -/// -/// ```no_run -/// use std::process::Command; -/// -/// let mut echo_hello = Command::new("sh"); -/// echo_hello.arg("-c").arg("echo hello"); -/// let hello_1 = echo_hello.output().expect("failed to execute process"); -/// let hello_2 = echo_hello.output().expect("failed to execute process"); -/// ``` -/// -/// Similarly, you can call builder methods after spawning a process and then -/// spawn a new process with the modified settings. -/// -/// ```no_run -/// use std::process::Command; -/// -/// let mut list_dir = Command::new("ls"); -/// -/// // Execute `ls` in the current directory of the program. -/// list_dir.status().expect("process failed to execute"); -/// -/// println!(); -/// -/// // Change `ls` to execute in the root directory. -/// list_dir.current_dir("/"); -/// -/// // And then execute `ls` again but in the root directory. -/// list_dir.status().expect("process failed to execute"); -/// ``` -#[stable(feature = "process", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Command")] -pub struct Command { - inner: imp::Command, -} - -/// Allows extension traits within `std`. -#[unstable(feature = "sealed", issue = "none")] -impl crate::sealed::Sealed for Command {} - -impl Command { - /// Constructs a new `Command` for launching the program at - /// path `program`, with the following default configuration: - /// - /// * No arguments to the program - /// * Inherit the current process's environment - /// * Inherit the current process's working directory - /// * Inherit stdin/stdout/stderr for [`spawn`] or [`status`], but create pipes for [`output`] - /// - /// [`spawn`]: Self::spawn - /// [`status`]: Self::status - /// [`output`]: Self::output - /// - /// Builder methods are provided to change these defaults and - /// otherwise configure the process. - /// - /// If `program` is not an absolute path, the `PATH` will be searched in - /// an OS-defined way. - /// - /// The search path to be used may be controlled by setting the - /// `PATH` environment variable on the Command, - /// but this has some implementation limitations on Windows - /// (see issue #37519). - /// - /// # Platform-specific behavior - /// - /// Note on Windows: For executable files with the .exe extension, - /// it can be omitted when specifying the program for this Command. - /// However, if the file has a different extension, - /// a filename including the extension needs to be provided, - /// otherwise the file won't be found. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("sh") - /// .spawn() - /// .expect("sh command failed to start"); - /// ``` - /// - /// # Caveats - /// - /// [`Command::new`] is only intended to accept the path of the program. If you pass a program - /// path along with arguments like `Command::new("ls -l").spawn()`, it will try to search for - /// `ls -l` literally. The arguments need to be passed separately, such as via [`arg`] or - /// [`args`]. - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .arg("-l") // arg passed separately - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - /// - /// [`arg`]: Self::arg - /// [`args`]: Self::args - #[stable(feature = "process", since = "1.0.0")] - pub fn new>(program: S) -> Command { - Command { inner: imp::Command::new(program.as_ref()) } - } - - /// Adds an argument to pass to the program. - /// - /// Only one argument can be passed per use. So instead of: - /// - /// ```no_run - /// # std::process::Command::new("sh") - /// .arg("-C /path/to/repo") - /// # ; - /// ``` - /// - /// usage would be: - /// - /// ```no_run - /// # std::process::Command::new("sh") - /// .arg("-C") - /// .arg("/path/to/repo") - /// # ; - /// ``` - /// - /// To pass multiple arguments see [`args`]. - /// - /// [`args`]: Command::args - /// - /// Note that the argument is not passed through a shell, but given - /// literally to the program. This means that shell syntax like quotes, - /// escaped characters, word splitting, glob patterns, variable substitution, - /// etc. have no effect. - /// - ///
- /// - /// On Windows, use caution with untrusted inputs. Most applications use the - /// standard convention for decoding arguments passed to them. These are safe to - /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files - /// use a non-standard way of decoding arguments. They are therefore vulnerable - /// to malicious input. - /// - /// In the case of `cmd.exe` this is especially important because a malicious - /// argument can potentially run arbitrary shell commands. - /// - /// See [Windows argument splitting][windows-args] for more details - /// or [`raw_arg`] for manually implementing non-standard argument encoding. - /// - /// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg - /// [windows-args]: crate::process#windows-argument-splitting - /// - ///
- /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .arg("-l") - /// .arg("-a") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn arg>(&mut self, arg: S) -> &mut Command { - self.inner.arg(arg.as_ref()); - self - } - - /// Adds multiple arguments to pass to the program. - /// - /// To pass a single argument see [`arg`]. - /// - /// [`arg`]: Command::arg - /// - /// Note that the arguments are not passed through a shell, but given - /// literally to the program. This means that shell syntax like quotes, - /// escaped characters, word splitting, glob patterns, variable substitution, etc. - /// have no effect. - /// - ///
- /// - /// On Windows, use caution with untrusted inputs. Most applications use the - /// standard convention for decoding arguments passed to them. These are safe to - /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files - /// use a non-standard way of decoding arguments. They are therefore vulnerable - /// to malicious input. - /// - /// In the case of `cmd.exe` this is especially important because a malicious - /// argument can potentially run arbitrary shell commands. - /// - /// See [Windows argument splitting][windows-args] for more details - /// or [`raw_arg`] for manually implementing non-standard argument encoding. - /// - /// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg - /// [windows-args]: crate::process#windows-argument-splitting - /// - ///
- /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .args(["-l", "-a"]) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn args(&mut self, args: I) -> &mut Command - where - I: IntoIterator, - S: AsRef, - { - for arg in args { - self.arg(arg.as_ref()); - } - self - } - - /// Inserts or updates an explicit environment variable mapping. - /// - /// This method allows you to add an environment variable mapping to the spawned process or - /// overwrite a previously set value. You can use [`Command::envs`] to set multiple environment - /// variables simultaneously. - /// - /// Child processes will inherit environment variables from their parent process by default. - /// Environment variables explicitly set using [`Command::env`] take precedence over inherited - /// variables. You can disable environment variable inheritance entirely using - /// [`Command::env_clear`] or for a single key using [`Command::env_remove`]. - /// - /// Note that environment variable names are case-insensitive (but - /// case-preserving) on Windows and case-sensitive on all other platforms. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .env("PATH", "/bin") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn env(&mut self, key: K, val: V) -> &mut Command - where - K: AsRef, - V: AsRef, - { - self.inner.env_mut().set(key.as_ref(), val.as_ref()); - self - } - - /// Inserts or updates multiple explicit environment variable mappings. - /// - /// This method allows you to add multiple environment variable mappings to the spawned process - /// or overwrite previously set values. You can use [`Command::env`] to set a single environment - /// variable. - /// - /// Child processes will inherit environment variables from their parent process by default. - /// Environment variables explicitly set using [`Command::envs`] take precedence over inherited - /// variables. You can disable environment variable inheritance entirely using - /// [`Command::env_clear`] or for a single key using [`Command::env_remove`]. - /// - /// Note that environment variable names are case-insensitive (but case-preserving) on Windows - /// and case-sensitive on all other platforms. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// use std::env; - /// use std::collections::HashMap; - /// - /// let filtered_env : HashMap = - /// env::vars().filter(|&(ref k, _)| - /// k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH" - /// ).collect(); - /// - /// Command::new("printenv") - /// .stdin(Stdio::null()) - /// .stdout(Stdio::inherit()) - /// .env_clear() - /// .envs(&filtered_env) - /// .spawn() - /// .expect("printenv failed to start"); - /// ``` - #[stable(feature = "command_envs", since = "1.19.0")] - pub fn envs(&mut self, vars: I) -> &mut Command - where - I: IntoIterator, - K: AsRef, - V: AsRef, - { - for (ref key, ref val) in vars { - self.inner.env_mut().set(key.as_ref(), val.as_ref()); - } - self - } - - /// Removes an explicitly set environment variable and prevents inheriting it from a parent - /// process. - /// - /// This method will remove the explicit value of an environment variable set via - /// [`Command::env`] or [`Command::envs`]. In addition, it will prevent the spawned child - /// process from inheriting that environment variable from its parent process. - /// - /// After calling [`Command::env_remove`], the value associated with its key from - /// [`Command::get_envs`] will be [`None`]. - /// - /// To clear all explicitly set environment variables and disable all environment variable - /// inheritance, you can use [`Command::env_clear`]. - /// - /// # Examples - /// - /// Prevent any inherited `GIT_DIR` variable from changing the target of the `git` command, - /// while allowing all other variables, like `GIT_AUTHOR_NAME`. - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("git") - /// .arg("commit") - /// .env_remove("GIT_DIR") - /// .spawn()?; - /// # std::io::Result::Ok(()) - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn env_remove>(&mut self, key: K) -> &mut Command { - self.inner.env_mut().remove(key.as_ref()); - self - } - - /// Clears all explicitly set environment variables and prevents inheriting any parent process - /// environment variables. - /// - /// This method will remove all explicitly added environment variables set via [`Command::env`] - /// or [`Command::envs`]. In addition, it will prevent the spawned child process from inheriting - /// any environment variable from its parent process. - /// - /// After calling [`Command::env_clear`], the iterator from [`Command::get_envs`] will be - /// empty. - /// - /// You can use [`Command::env_remove`] to clear a single mapping. - /// - /// # Examples - /// - /// The behavior of `sort` is affected by `LANG` and `LC_*` environment variables. - /// Clearing the environment makes `sort`'s behavior independent of the parent processes' language. - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("sort") - /// .arg("file.txt") - /// .env_clear() - /// .spawn()?; - /// # std::io::Result::Ok(()) - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn env_clear(&mut self) -> &mut Command { - self.inner.env_mut().clear(); - self - } - - /// Sets the working directory for the child process. - /// - /// # Platform-specific behavior - /// - /// If the program path is relative (e.g., `"./script.sh"`), it's ambiguous - /// whether it should be interpreted relative to the parent's working - /// directory or relative to `current_dir`. The behavior in this case is - /// platform specific and unstable, and it's recommended to use - /// [`canonicalize`] to get an absolute program path instead. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .current_dir("/bin") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - /// - /// [`canonicalize`]: crate::fs::canonicalize - #[stable(feature = "process", since = "1.0.0")] - pub fn current_dir>(&mut self, dir: P) -> &mut Command { - self.inner.cwd(dir.as_ref().as_ref()); - self - } - - /// Configuration for the child process's standard input (stdin) handle. - /// - /// Defaults to [`inherit`] when used with [`spawn`] or [`status`], and - /// defaults to [`piped`] when used with [`output`]. - /// - /// [`inherit`]: Stdio::inherit - /// [`piped`]: Stdio::piped - /// [`spawn`]: Self::spawn - /// [`status`]: Self::status - /// [`output`]: Self::output - /// - /// # Examples - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// Command::new("ls") - /// .stdin(Stdio::null()) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn stdin>(&mut self, cfg: T) -> &mut Command { - self.inner.stdin(cfg.into().0); - self - } - - /// Configuration for the child process's standard output (stdout) handle. - /// - /// Defaults to [`inherit`] when used with [`spawn`] or [`status`], and - /// defaults to [`piped`] when used with [`output`]. - /// - /// [`inherit`]: Stdio::inherit - /// [`piped`]: Stdio::piped - /// [`spawn`]: Self::spawn - /// [`status`]: Self::status - /// [`output`]: Self::output - /// - /// # Examples - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// Command::new("ls") - /// .stdout(Stdio::null()) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn stdout>(&mut self, cfg: T) -> &mut Command { - self.inner.stdout(cfg.into().0); - self - } - - /// Configuration for the child process's standard error (stderr) handle. - /// - /// Defaults to [`inherit`] when used with [`spawn`] or [`status`], and - /// defaults to [`piped`] when used with [`output`]. - /// - /// [`inherit`]: Stdio::inherit - /// [`piped`]: Stdio::piped - /// [`spawn`]: Self::spawn - /// [`status`]: Self::status - /// [`output`]: Self::output - /// - /// # Examples - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// Command::new("ls") - /// .stderr(Stdio::null()) - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn stderr>(&mut self, cfg: T) -> &mut Command { - self.inner.stderr(cfg.into().0); - self - } - - /// Executes the command as a child process, returning a handle to it. - /// - /// By default, stdin, stdout and stderr are inherited from the parent. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// Command::new("ls") - /// .spawn() - /// .expect("ls command failed to start"); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn spawn(&mut self) -> io::Result { - self.inner.spawn(imp::Stdio::Inherit, true).map(Child::from_inner) - } - - /// Executes the command as a child process, waiting for it to finish and - /// collecting all of its output. - /// - /// By default, stdout and stderr are captured (and used to provide the - /// resulting output). Stdin is not inherited from the parent and any - /// attempt by the child process to read from the stdin stream will result - /// in the stream immediately closing. - /// - /// # Examples - /// - /// ```should_panic - /// use std::process::Command; - /// use std::io::{self, Write}; - /// let output = Command::new("/bin/cat") - /// .arg("file.txt") - /// .output()?; - /// - /// println!("status: {}", output.status); - /// io::stdout().write_all(&output.stdout)?; - /// io::stderr().write_all(&output.stderr)?; - /// - /// assert!(output.status.success()); - /// # io::Result::Ok(()) - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn output(&mut self) -> io::Result { - let (status, stdout, stderr) = imp::output(&mut self.inner)?; - Ok(Output { status: ExitStatus(status), stdout, stderr }) - } - - /// Executes a command as a child process, waiting for it to finish and - /// collecting its status. - /// - /// By default, stdin, stdout and stderr are inherited from the parent. - /// - /// # Examples - /// - /// ```should_panic - /// use std::process::Command; - /// - /// let status = Command::new("/bin/cat") - /// .arg("file.txt") - /// .status() - /// .expect("failed to execute process"); - /// - /// println!("process finished with: {status}"); - /// - /// assert!(status.success()); - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn status(&mut self) -> io::Result { - self.inner - .spawn(imp::Stdio::Inherit, true) - .map(Child::from_inner) - .and_then(|mut p| p.wait()) - } - - /// Returns the path to the program that was given to [`Command::new`]. - /// - /// # Examples - /// - /// ``` - /// use std::process::Command; - /// - /// let cmd = Command::new("echo"); - /// assert_eq!(cmd.get_program(), "echo"); - /// ``` - #[must_use] - #[stable(feature = "command_access", since = "1.57.0")] - pub fn get_program(&self) -> &OsStr { - self.inner.get_program() - } - - /// Returns an iterator of the arguments that will be passed to the program. - /// - /// This does not include the path to the program as the first argument; - /// it only includes the arguments specified with [`Command::arg`] and - /// [`Command::args`]. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::process::Command; - /// - /// let mut cmd = Command::new("echo"); - /// cmd.arg("first").arg("second"); - /// let args: Vec<&OsStr> = cmd.get_args().collect(); - /// assert_eq!(args, &["first", "second"]); - /// ``` - #[stable(feature = "command_access", since = "1.57.0")] - pub fn get_args(&self) -> CommandArgs<'_> { - CommandArgs { inner: self.inner.get_args() } - } - - /// Returns an iterator of the environment variables explicitly set for the child process. - /// - /// Environment variables explicitly set using [`Command::env`], [`Command::envs`], and - /// [`Command::env_remove`] can be retrieved with this method. - /// - /// Note that this output does not include environment variables inherited from the parent - /// process. - /// - /// Each element is a tuple key/value pair `(&OsStr, Option<&OsStr>)`. A [`None`] value - /// indicates its key was explicitly removed via [`Command::env_remove`]. The associated key for - /// the [`None`] value will no longer inherit from its parent process. - /// - /// An empty iterator can indicate that no explicit mappings were added or that - /// [`Command::env_clear`] was called. After calling [`Command::env_clear`], the child process - /// will not inherit any environment variables from its parent process. - /// - /// # Examples - /// - /// ``` - /// use std::ffi::OsStr; - /// use std::process::Command; - /// - /// let mut cmd = Command::new("ls"); - /// cmd.env("TERM", "dumb").env_remove("TZ"); - /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect(); - /// assert_eq!(envs, &[ - /// (OsStr::new("TERM"), Some(OsStr::new("dumb"))), - /// (OsStr::new("TZ"), None) - /// ]); - /// ``` - #[stable(feature = "command_access", since = "1.57.0")] - pub fn get_envs(&self) -> CommandEnvs<'_> { - CommandEnvs { iter: self.inner.get_envs() } - } - - /// Returns the working directory for the child process. - /// - /// This returns [`None`] if the working directory will not be changed. - /// - /// # Examples - /// - /// ``` - /// use std::path::Path; - /// use std::process::Command; - /// - /// let mut cmd = Command::new("ls"); - /// assert_eq!(cmd.get_current_dir(), None); - /// cmd.current_dir("/bin"); - /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin"))); - /// ``` - #[must_use] - #[stable(feature = "command_access", since = "1.57.0")] - pub fn get_current_dir(&self) -> Option<&Path> { - self.inner.get_current_dir() - } - - /// Returns whether the environment will be cleared for the child process. - /// - /// This returns `true` if [`Command::env_clear`] was called, and `false` otherwise. - /// When `true`, the child process will not inherit any environment variables from - /// its parent process. - /// - /// # Examples - /// - /// ``` - /// #![feature(command_resolved_envs)] - /// use std::process::Command; - /// - /// let mut cmd = Command::new("ls"); - /// assert_eq!(cmd.get_env_clear(), false); - /// - /// cmd.env_clear(); - /// assert_eq!(cmd.get_env_clear(), true); - /// ``` - #[must_use] - #[unstable(feature = "command_resolved_envs", issue = "149070")] - pub fn get_env_clear(&self) -> bool { - self.inner.get_env_clear() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Command { - /// Format the program and arguments of a Command for display. Any - /// non-utf8 data is lossily converted using the utf8 replacement - /// character. - /// - /// The default format approximates a shell invocation of the program along with its - /// arguments. It does not include most of the other command properties. The output is not guaranteed to work - /// (e.g. due to lack of shell-escaping or differences in path resolution). - /// On some platforms you can use [the alternate syntax] to show more fields. - /// - /// Note that the debug implementation is platform-specific. - /// - /// [the alternate syntax]: fmt#sign0 - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl AsInner for Command { - #[inline] - fn as_inner(&self) -> &imp::Command { - &self.inner - } -} - -impl AsInnerMut for Command { - #[inline] - fn as_inner_mut(&mut self) -> &mut imp::Command { - &mut self.inner - } -} - -/// An iterator over the command arguments. -/// -/// This struct is created by [`Command::get_args`]. See its documentation for -/// more. -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "command_access", since = "1.57.0")] -#[derive(Debug)] -pub struct CommandArgs<'a> { - inner: imp::CommandArgs<'a>, -} - -#[stable(feature = "command_access", since = "1.57.0")] -impl<'a> Iterator for CommandArgs<'a> { - type Item = &'a OsStr; - fn next(&mut self) -> Option<&'a OsStr> { - self.inner.next() - } - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "command_access", since = "1.57.0")] -impl<'a> ExactSizeIterator for CommandArgs<'a> { - fn len(&self) -> usize { - self.inner.len() - } - fn is_empty(&self) -> bool { - self.inner.is_empty() - } -} - -/// An iterator over the command environment variables. -/// -/// This struct is created by -/// [`Command::get_envs`][crate::process::Command::get_envs]. See its -/// documentation for more. -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "command_access", since = "1.57.0")] -pub struct CommandEnvs<'a> { - iter: imp::CommandEnvs<'a>, -} - -#[stable(feature = "command_access", since = "1.57.0")] -impl<'a> Iterator for CommandEnvs<'a> { - type Item = (&'a OsStr, Option<&'a OsStr>); - - fn next(&mut self) -> Option { - self.iter.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "command_access", since = "1.57.0")] -impl<'a> ExactSizeIterator for CommandEnvs<'a> { - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "command_access", since = "1.57.0")] -impl<'a> fmt::Debug for CommandEnvs<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.iter.fmt(f) - } -} - -/// The output of a finished process. -/// -/// This is returned in a Result by either the [`output`] method of a -/// [`Command`], or the [`wait_with_output`] method of a [`Child`] -/// process. -/// -/// [`output`]: Command::output -/// [`wait_with_output`]: Child::wait_with_output -#[derive(PartialEq, Eq, Clone)] -#[stable(feature = "process", since = "1.0.0")] -pub struct Output { - /// The status (exit code) of the process. - #[stable(feature = "process", since = "1.0.0")] - pub status: ExitStatus, - /// The data that the process wrote to stdout. - #[stable(feature = "process", since = "1.0.0")] - pub stdout: Vec, - /// The data that the process wrote to stderr. - #[stable(feature = "process", since = "1.0.0")] - pub stderr: Vec, -} - -impl Output { - /// Returns an error if a nonzero exit status was received. - /// - /// If the [`Command`] exited successfully, - /// `self` is returned. - /// - /// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok) - /// on [`Output.status`](Output::status). - /// - /// Note that this will throw away the [`Output::stderr`] field in the error case. - /// If the child process outputs useful informantion to stderr, you can: - /// * Use `cmd.stderr(Stdio::inherit())` to forward the - /// stderr child process to the parent's stderr, - /// usually printing it to console where the user can see it. - /// This is usually correct for command-line applications. - /// * Capture `stderr` using a custom error type. - /// This is usually correct for libraries. - /// - /// # 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; - /// assert!(Command::new("false").output().unwrap().exit_ok().is_err()); - /// # } - /// ``` - #[unstable(feature = "exit_status_error", issue = "84908")] - pub fn exit_ok(self) -> Result { - self.status.exit_ok()?; - Ok(self) - } -} - -// If either stderr or stdout are valid utf8 strings it prints the valid -// strings, otherwise it prints the byte sequence instead -#[stable(feature = "process_output_debug", since = "1.7.0")] -impl fmt::Debug for Output { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let stdout_utf8 = str::from_utf8(&self.stdout); - let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { - Ok(ref s) => s, - Err(_) => &self.stdout, - }; - - let stderr_utf8 = str::from_utf8(&self.stderr); - let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { - Ok(ref s) => s, - Err(_) => &self.stderr, - }; - - fmt.debug_struct("Output") - .field("status", &self.status) - .field("stdout", stdout_debug) - .field("stderr", stderr_debug) - .finish() - } -} - -/// Describes what to do with a standard I/O stream for a child process when -/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`]. -/// -/// [`stdin`]: Command::stdin -/// [`stdout`]: Command::stdout -/// [`stderr`]: Command::stderr -#[stable(feature = "process", since = "1.0.0")] -pub struct Stdio(imp::Stdio); - -impl Stdio { - /// A new pipe should be arranged to connect the parent and child processes. - /// - /// # Examples - /// - /// With stdout: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::piped()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n"); - /// // Nothing echoed to console - /// ``` - /// - /// With stdin: - /// - /// ```no_run - /// use std::io::Write; - /// use std::process::{Command, Stdio}; - /// - /// let mut child = Command::new("rev") - /// .stdin(Stdio::piped()) - /// .stdout(Stdio::piped()) - /// .spawn() - /// .expect("Failed to spawn child process"); - /// - /// let mut stdin = child.stdin.take().expect("Failed to open stdin"); - /// std::thread::spawn(move || { - /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); - /// }); - /// - /// let output = child.wait_with_output().expect("Failed to read stdout"); - /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH"); - /// ``` - /// - /// Writing more than a pipe buffer's worth of input to stdin without also reading - /// stdout and stderr at the same time may cause a deadlock. - /// This is an issue when running any program that doesn't guarantee that it reads - /// its entire stdin before writing more than a pipe buffer's worth of output. - /// The size of a pipe buffer varies on different targets. - /// - #[must_use] - #[stable(feature = "process", since = "1.0.0")] - pub fn piped() -> Stdio { - Stdio(imp::Stdio::MakePipe) - } - - /// The child inherits from the corresponding parent descriptor. - /// - /// # Examples - /// - /// With stdout: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::inherit()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); - /// // "Hello, world!" echoed to console - /// ``` - /// - /// With stdin: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// use std::io::{self, Write}; - /// - /// let output = Command::new("rev") - /// .stdin(Stdio::inherit()) - /// .stdout(Stdio::piped()) - /// .output()?; - /// - /// print!("You piped in the reverse of: "); - /// io::stdout().write_all(&output.stdout)?; - /// # io::Result::Ok(()) - /// ``` - #[must_use] - #[stable(feature = "process", since = "1.0.0")] - pub fn inherit() -> Stdio { - Stdio(imp::Stdio::Inherit) - } - - /// This stream will be ignored. This is the equivalent of attaching the - /// stream to `/dev/null`. - /// - /// # Examples - /// - /// With stdout: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::null()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); - /// // Nothing echoed to console - /// ``` - /// - /// With stdin: - /// - /// ```no_run - /// use std::process::{Command, Stdio}; - /// - /// let output = Command::new("rev") - /// .stdin(Stdio::null()) - /// .stdout(Stdio::piped()) - /// .output() - /// .expect("Failed to execute command"); - /// - /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); - /// // Ignores any piped-in input - /// ``` - #[must_use] - #[stable(feature = "process", since = "1.0.0")] - pub fn null() -> Stdio { - Stdio(imp::Stdio::Null) - } - - /// Returns `true` if this requires [`Command`] to create a new pipe. - /// - /// # Example - /// - /// ``` - /// #![feature(stdio_makes_pipe)] - /// use std::process::Stdio; - /// - /// let io = Stdio::piped(); - /// assert_eq!(io.makes_pipe(), true); - /// ``` - #[unstable(feature = "stdio_makes_pipe", issue = "98288")] - pub fn makes_pipe(&self) -> bool { - matches!(self.0, imp::Stdio::MakePipe) - } -} - -impl FromInner for Stdio { - fn from_inner(inner: imp::Stdio) -> Stdio { - Stdio(inner) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Stdio { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Stdio").finish_non_exhaustive() - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - /// Converts a [`ChildStdin`] into a [`Stdio`]. - /// - /// # Examples - /// - /// `ChildStdin` will be converted to `Stdio` using `Stdio::from` under the hood. - /// - /// ```rust,no_run - /// use std::process::{Command, Stdio}; - /// - /// let reverse = Command::new("rev") - /// .stdin(Stdio::piped()) - /// .spawn() - /// .expect("failed reverse command"); - /// - /// let _echo = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(reverse.stdin.unwrap()) // Converted into a Stdio here - /// .output() - /// .expect("failed echo command"); - /// - /// // "!dlrow ,olleH" echoed to console - /// ``` - fn from(child: ChildStdin) -> Stdio { - Stdio::from_inner(child.into_inner().into()) - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - /// Converts a [`ChildStdout`] into a [`Stdio`]. - /// - /// # Examples - /// - /// `ChildStdout` will be converted to `Stdio` using `Stdio::from` under the hood. - /// - /// ```rust,no_run - /// use std::process::{Command, Stdio}; - /// - /// let hello = Command::new("echo") - /// .arg("Hello, world!") - /// .stdout(Stdio::piped()) - /// .spawn() - /// .expect("failed echo command"); - /// - /// let reverse = Command::new("rev") - /// .stdin(hello.stdout.unwrap()) // Converted into a Stdio here - /// .output() - /// .expect("failed reverse command"); - /// - /// assert_eq!(reverse.stdout, b"!dlrow ,olleH\n"); - /// ``` - fn from(child: ChildStdout) -> Stdio { - Stdio::from_inner(child.into_inner().into()) - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - /// Converts a [`ChildStderr`] into a [`Stdio`]. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::process::{Command, Stdio}; - /// - /// let reverse = Command::new("rev") - /// .arg("non_existing_file.txt") - /// .stderr(Stdio::piped()) - /// .spawn() - /// .expect("failed reverse command"); - /// - /// let cat = Command::new("cat") - /// .arg("-") - /// .stdin(reverse.stderr.unwrap()) // Converted into a Stdio here - /// .output() - /// .expect("failed echo command"); - /// - /// assert_eq!( - /// String::from_utf8_lossy(&cat.stdout), - /// "rev: cannot open non_existing_file.txt: No such file or directory\n" - /// ); - /// ``` - fn from(child: ChildStderr) -> Stdio { - Stdio::from_inner(child.into_inner().into()) - } -} - -#[stable(feature = "stdio_from", since = "1.20.0")] -impl From for Stdio { - /// Converts a [`File`](fs::File) into a [`Stdio`]. - /// - /// # Examples - /// - /// `File` will be converted to `Stdio` using `Stdio::from` under the hood. - /// - /// ```rust,no_run - /// use std::fs::File; - /// use std::process::Command; - /// - /// // With the `foo.txt` file containing "Hello, world!" - /// let file = File::open("foo.txt")?; - /// - /// let reverse = Command::new("rev") - /// .stdin(file) // Implicit File conversion into a Stdio - /// .output()?; - /// - /// assert_eq!(reverse.stdout, b"!dlrow ,olleH"); - /// # std::io::Result::Ok(()) - /// ``` - fn from(file: fs::File) -> Stdio { - Stdio::from_inner(file.into_inner().into()) - } -} - -#[stable(feature = "stdio_from_stdio", since = "1.74.0")] -impl From for Stdio { - /// Redirect command stdout/stderr to our stdout - /// - /// # Examples - /// - /// ```rust - /// #![feature(exit_status_error)] - /// use std::io; - /// use std::process::Command; - /// - /// # fn test() -> Result<(), Box> { - /// let output = Command::new("whoami") - // "whoami" is a command which exists on both Unix and Windows, - // and which succeeds, producing some stdout output but no stderr. - /// .stdout(io::stdout()) - /// .output()?; - /// output.status.exit_ok()?; - /// assert!(output.stdout.is_empty()); - /// # Ok(()) - /// # } - /// # - /// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { - /// # test().unwrap(); - /// # } - /// ``` - fn from(inherit: io::Stdout) -> Stdio { - Stdio::from_inner(inherit.into()) - } -} - -#[stable(feature = "stdio_from_stdio", since = "1.74.0")] -impl From for Stdio { - /// Redirect command stdout/stderr to our stderr - /// - /// # Examples - /// - /// ```rust - /// #![feature(exit_status_error)] - /// use std::io; - /// use std::process::Command; - /// - /// # fn test() -> Result<(), Box> { - /// let output = Command::new("whoami") - /// .stdout(io::stderr()) - /// .output()?; - /// output.status.exit_ok()?; - /// assert!(output.stdout.is_empty()); - /// # Ok(()) - /// # } - /// # - /// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { - /// # test().unwrap(); - /// # } - /// ``` - fn from(inherit: io::Stderr) -> Stdio { - Stdio::from_inner(inherit.into()) - } -} - -#[stable(feature = "anonymous_pipe", since = "1.87.0")] -impl From for Stdio { - fn from(pipe: io::PipeWriter) -> Self { - Stdio::from_inner(pipe.into_inner().into()) - } -} - -#[stable(feature = "anonymous_pipe", since = "1.87.0")] -impl From for Stdio { - fn from(pipe: io::PipeReader) -> Self { - Stdio::from_inner(pipe.into_inner().into()) - } -} - -/// Describes the result of a process after it has terminated. -/// -/// This `struct` is used to represent the exit status or other termination of a child process. -/// Child processes are created via the [`Command`] struct and their exit -/// status is exposed through the [`status`] method, or the [`wait`] method -/// of a [`Child`] process. -/// -/// An `ExitStatus` represents every possible disposition of a process. On Unix this -/// is the **wait status**. It is *not* simply an *exit status* (a value passed to `exit`). -/// -/// For proper error reporting of failed processes, print the value of `ExitStatus` or -/// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display). -/// -/// # Differences from `ExitCode` -/// -/// [`ExitCode`] is intended for terminating the currently running process, via -/// the `Termination` trait, in contrast to `ExitStatus`, which represents the -/// termination of a child process. These APIs are separate due to platform -/// compatibility differences and their expected usage; it is not generally -/// possible to exactly reproduce an `ExitStatus` from a child for the current -/// process after the fact. -/// -/// [`status`]: Command::status -/// [`wait`]: Child::wait -// -// We speak slightly loosely (here and in various other places in the stdlib docs) about `exit` -// vs `_exit`. Naming of Unix system calls is not standardised across Unices, so terminology is a -// matter of convention and tradition. For clarity we usually speak of `exit`, even when we might -// mean an underlying system call such as `_exit`. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[stable(feature = "process", since = "1.0.0")] -pub struct ExitStatus(imp::ExitStatus); - -/// The default value is one which indicates successful completion. -#[stable(feature = "process_exitstatus_default", since = "1.73.0")] -impl Default for ExitStatus { - fn default() -> Self { - // Ideally this would be done by ExitCode::default().into() but that is complicated. - ExitStatus::from_inner(imp::ExitStatus::default()) - } -} - -/// Allows extension traits within `std`. -#[unstable(feature = "sealed", issue = "none")] -impl crate::sealed::Sealed for ExitStatus {} - -impl ExitStatus { - /// Was termination successful? Returns a `Result`. - /// - /// # Examples - /// - /// ``` - /// #![feature(exit_status_error)] - /// # if cfg!(all(unix, not(all(target_vendor = "apple", not(target_os = "macos"))))) { - /// use std::process::Command; - /// - /// let status = Command::new("ls") - /// .arg("/dev/nonexistent") - /// .status() - /// .expect("ls could not be executed"); - /// - /// println!("ls: {status}"); - /// status.exit_ok().expect_err("/dev/nonexistent could be listed!"); - /// # } // cfg!(unix) - /// ``` - #[unstable(feature = "exit_status_error", issue = "84908")] - pub fn exit_ok(&self) -> Result<(), ExitStatusError> { - self.0.exit_ok().map_err(ExitStatusError) - } - - /// Was termination successful? Signal termination is not considered a - /// success, and success is defined as a zero exit status. - /// - /// # Examples - /// - /// ```rust,no_run - /// use std::process::Command; - /// - /// let status = Command::new("mkdir") - /// .arg("projects") - /// .status() - /// .expect("failed to execute mkdir"); - /// - /// if status.success() { - /// println!("'projects/' directory created"); - /// } else { - /// println!("failed to create 'projects/' directory: {status}"); - /// } - /// ``` - #[must_use] - #[stable(feature = "process", since = "1.0.0")] - pub fn success(&self) -> bool { - self.0.exit_ok().is_ok() - } - - /// Returns the exit code of the process, if any. - /// - /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the - /// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8 - /// bits, and that values that didn't come from a program's call to `exit` may be invented by the - /// runtime system (often, for example, 255, 254, 127 or 126). - /// - /// On Unix, this will return `None` if the process was terminated by a signal. - /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt) is an - /// extension trait for extracting any such signal, and other details, from the `ExitStatus`. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// let status = Command::new("mkdir") - /// .arg("projects") - /// .status() - /// .expect("failed to execute mkdir"); - /// - /// match status.code() { - /// Some(code) => println!("Exited with status code: {code}"), - /// None => println!("Process terminated by signal") - /// } - /// ``` - #[must_use] - #[stable(feature = "process", since = "1.0.0")] - pub fn code(&self) -> Option { - self.0.code() - } -} - -impl AsInner for ExitStatus { - #[inline] - fn as_inner(&self) -> &imp::ExitStatus { - &self.0 - } -} - -impl FromInner for ExitStatus { - fn from_inner(s: imp::ExitStatus) -> ExitStatus { - ExitStatus(s) - } -} - -#[stable(feature = "process", since = "1.0.0")] -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// Allows extension traits within `std`. -#[unstable(feature = "sealed", issue = "none")] -impl crate::sealed::Sealed for ExitStatusError {} - -/// Describes the result of a process after it has failed -/// -/// Produced by the [`.exit_ok`](ExitStatus::exit_ok) method on [`ExitStatus`]. -/// -/// # Examples -/// -/// ``` -/// #![feature(exit_status_error)] -/// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { -/// use std::process::{Command, ExitStatusError}; -/// -/// fn run(cmd: &str) -> Result<(), ExitStatusError> { -/// Command::new(cmd).status().unwrap().exit_ok()?; -/// Ok(()) -/// } -/// -/// run("true").unwrap(); -/// run("false").unwrap_err(); -/// # } // cfg!(unix) -/// ``` -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[unstable(feature = "exit_status_error", issue = "84908")] -// The definition of imp::ExitStatusError should ideally be such that -// Result<(), imp::ExitStatusError> has an identical representation to imp::ExitStatus. -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`. - /// - /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the - /// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8 - /// bits, and that values that didn't come from a program's call to `exit` may be invented by the - /// runtime system (often, for example, 255, 254, 127 or 126). - /// - /// On Unix, this will return `None` if the process was terminated by a signal. If you want to - /// handle such situations specially, consider using methods from - /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt). - /// - /// If the process finished by calling `exit` with a nonzero value, this will return - /// that exit status. - /// - /// If the error was something else, it will return `None`. - /// - /// If the process exited successfully (ie, by calling `exit(0)`), there is no - /// `ExitStatusError`. So the return value from `ExitStatusError::code()` is always nonzero. - /// - /// # Examples - /// - /// ``` - /// #![feature(exit_status_error)] - /// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] { - /// use std::process::Command; - /// - /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err(); - /// assert_eq!(bad.code(), Some(1)); - /// # } // #[cfg(unix)] - /// ``` - #[must_use] - pub fn code(&self) -> Option { - self.code_nonzero().map(Into::into) - } - - /// Reports the exit code, if applicable, from an `ExitStatusError`, as a [`NonZero`]. - /// - /// This is exactly like [`code()`](Self::code), except that it returns a [NonZero]<[i32]>. - /// - /// Plain `code`, returning a plain integer, is provided because it is often more convenient. - /// The returned value from `code()` is indeed also nonzero; use `code_nonzero()` when you want - /// a type-level guarantee of nonzeroness. - /// - /// # Examples - /// - /// ``` - /// #![feature(exit_status_error)] - /// - /// # if cfg!(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos"))))) { - /// use std::num::NonZero; - /// use std::process::Command; - /// - /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err(); - /// assert_eq!(bad.code_nonzero().unwrap(), NonZero::new(1).unwrap()); - /// # } // cfg!(unix) - /// ``` - #[must_use] - pub fn code_nonzero(&self) -> Option> { - self.0.code() - } - - /// Converts an `ExitStatusError` (back) to an `ExitStatus`. - #[must_use] - pub fn into_status(&self) -> ExitStatus { - ExitStatus(self.0.into()) - } -} - -#[unstable(feature = "exit_status_error", issue = "84908")] -impl From for ExitStatus { - fn from(error: ExitStatusError) -> Self { - Self(error.0.into()) - } -} - -#[unstable(feature = "exit_status_error", issue = "84908")] -impl fmt::Display for ExitStatusError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "process exited unsuccessfully: {}", self.into_status()) - } -} - -#[unstable(feature = "exit_status_error", issue = "84908")] -impl crate::error::Error for ExitStatusError {} - -/// This type represents the status code the current process can return -/// to its parent under normal termination. -/// -/// `ExitCode` is intended to be consumed only by the standard library (via -/// [`Termination::report()`]). For forwards compatibility with potentially -/// unusual targets, this type currently does not provide `Eq`, `Hash`, or -/// access to the raw value. This type does provide `PartialEq` for -/// comparison, but note that there may potentially be multiple failure -/// codes, some of which will _not_ compare equal to `ExitCode::FAILURE`. -/// The standard library provides the canonical `SUCCESS` and `FAILURE` -/// exit codes as well as `From for ExitCode` for constructing other -/// arbitrary exit codes. -/// -/// # Portability -/// -/// Numeric values used in this type don't have portable meanings, and -/// different platforms may mask different amounts of them. -/// -/// For the platform's canonical successful and unsuccessful codes, see -/// the [`SUCCESS`] and [`FAILURE`] associated items. -/// -/// [`SUCCESS`]: ExitCode::SUCCESS -/// [`FAILURE`]: ExitCode::FAILURE -/// -/// # Differences from `ExitStatus` -/// -/// `ExitCode` is intended for terminating the currently running process, via -/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the -/// termination of a child process. These APIs are separate due to platform -/// compatibility differences and their expected usage; it is not generally -/// possible to exactly reproduce an `ExitStatus` from a child for the current -/// process after the fact. -/// -/// # Examples -/// -/// `ExitCode` can be returned from the `main` function of a crate, as it implements -/// [`Termination`]: -/// -/// ``` -/// use std::process::ExitCode; -/// # fn check_foo() -> bool { true } -/// -/// fn main() -> ExitCode { -/// if !check_foo() { -/// return ExitCode::from(42); -/// } -/// -/// ExitCode::SUCCESS -/// } -/// ``` -#[derive(Clone, Copy, Debug, PartialEq)] -#[stable(feature = "process_exitcode", since = "1.61.0")] -pub struct ExitCode(imp::ExitCode); - -/// Allows extension traits within `std`. -#[unstable(feature = "sealed", issue = "none")] -impl crate::sealed::Sealed for ExitCode {} - -#[stable(feature = "process_exitcode", since = "1.61.0")] -impl ExitCode { - /// The canonical `ExitCode` for successful termination on this platform. - /// - /// Note that a `()`-returning `main` implicitly results in a successful - /// termination, so there's no need to return this from `main` unless - /// you're also returning other possible codes. - #[stable(feature = "process_exitcode", since = "1.61.0")] - pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS); - - /// The canonical `ExitCode` for unsuccessful termination on this platform. - /// - /// If you're only returning this and `SUCCESS` from `main`, consider - /// instead returning `Err(_)` and `Ok(())` respectively, which will - /// return the same codes (but will also `eprintln!` the error). - #[stable(feature = "process_exitcode", since = "1.61.0")] - pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); - - /// Exit the current process with the given `ExitCode`. - /// - /// Note that this has the same caveats as [`process::exit()`][exit], namely that this function - /// terminates the process immediately, so no destructors on the current stack or any other - /// thread's stack will be run. Also see those docs for some important notes on interop with C - /// code. If a clean shutdown is needed, it is recommended to simply return this ExitCode from - /// the `main` function, as demonstrated in the [type documentation](#examples). - /// - /// # Differences from `process::exit()` - /// - /// `process::exit()` accepts any `i32` value as the exit code for the process; however, there - /// are platforms that only use a subset of that value (see [`process::exit` platform-specific - /// behavior][exit#platform-specific-behavior]). `ExitCode` exists because of this; only - /// `ExitCode`s that are supported by a majority of our platforms can be created, so those - /// problems don't exist (as much) with this method. - /// - /// # Examples - /// - /// ``` - /// #![feature(exitcode_exit_method)] - /// # use std::process::ExitCode; - /// # use std::fmt; - /// # enum UhOhError { GenericProblem, Specific, WithCode { exit_code: ExitCode, _x: () } } - /// # impl fmt::Display for UhOhError { - /// # fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { unimplemented!() } - /// # } - /// // there's no way to gracefully recover from an UhOhError, so we just - /// // print a message and exit - /// fn handle_unrecoverable_error(err: UhOhError) -> ! { - /// eprintln!("UH OH! {err}"); - /// let code = match err { - /// UhOhError::GenericProblem => ExitCode::FAILURE, - /// UhOhError::Specific => ExitCode::from(3), - /// UhOhError::WithCode { exit_code, .. } => exit_code, - /// }; - /// code.exit_process() - /// } - /// ``` - #[unstable(feature = "exitcode_exit_method", issue = "97100")] - pub fn exit_process(self) -> ! { - exit(self.to_i32()) - } -} - -impl ExitCode { - // This is private/perma-unstable because ExitCode is opaque; we don't know that i32 will serve - // all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we - // likely want to isolate users anything that could restrict the platform specific - // representation of an ExitCode - // - // More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426 - /// Converts an `ExitCode` into an i32 - #[unstable( - feature = "process_exitcode_internals", - reason = "exposed only for libstd", - issue = "none" - )] - #[inline] - #[doc(hidden)] - pub fn to_i32(self) -> i32 { - self.0.as_i32() - } -} - -/// The default value is [`ExitCode::SUCCESS`] -#[stable(feature = "process_exitcode_default", since = "1.75.0")] -impl Default for ExitCode { - fn default() -> Self { - ExitCode::SUCCESS - } -} - -#[stable(feature = "process_exitcode", since = "1.61.0")] -impl From for ExitCode { - /// Constructs an `ExitCode` from an arbitrary u8 value. - fn from(code: u8) -> Self { - ExitCode(imp::ExitCode::from(code)) - } -} - -impl AsInner for ExitCode { - #[inline] - fn as_inner(&self) -> &imp::ExitCode { - &self.0 - } -} - -impl FromInner for ExitCode { - fn from_inner(s: imp::ExitCode) -> ExitCode { - ExitCode(s) - } -} - -impl Child { - /// Forces the child process to exit. If the child has already exited, `Ok(())` - /// is returned. - /// - /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function. - /// - /// This is equivalent to sending a SIGKILL on Unix platforms. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut command = Command::new("yes"); - /// if let Ok(mut child) = command.spawn() { - /// child.kill().expect("command couldn't be killed"); - /// } else { - /// println!("yes command didn't start"); - /// } - /// ``` - /// - /// [`ErrorKind`]: io::ErrorKind - /// [`InvalidInput`]: io::ErrorKind::InvalidInput - #[stable(feature = "process", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "child_kill")] - pub fn kill(&mut self) -> io::Result<()> { - self.handle.kill() - } - - /// Returns the OS-assigned process identifier associated with this child. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut command = Command::new("ls"); - /// if let Ok(child) = command.spawn() { - /// println!("Child's ID is {}", child.id()); - /// } else { - /// println!("ls command didn't start"); - /// } - /// ``` - #[must_use] - #[stable(feature = "process_id", since = "1.3.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "child_id")] - pub fn id(&self) -> u32 { - self.handle.id() - } - - /// Waits for the child to exit completely, returning the status that it - /// exited with. This function will continue to have the same return value - /// after it has been called at least once. - /// - /// The stdin handle to the child process, if any, will be closed - /// before waiting. This helps avoid deadlock: it ensures that the - /// child does not block waiting for input from the parent, while - /// the parent waits for the child to exit. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut command = Command::new("ls"); - /// if let Ok(mut child) = command.spawn() { - /// child.wait().expect("command wasn't running"); - /// println!("Child has finished its execution!"); - /// } else { - /// println!("ls command didn't start"); - /// } - /// ``` - #[stable(feature = "process", since = "1.0.0")] - pub fn wait(&mut self) -> io::Result { - drop(self.stdin.take()); - self.handle.wait().map(ExitStatus) - } - - /// Attempts to collect the exit status of the child if it has already - /// exited. - /// - /// This function will not block the calling thread and will only - /// check to see if the child process has exited or not. If the child has - /// exited then on Unix the process ID is reaped. This function is - /// guaranteed to repeatedly return a successful exit status so long as the - /// child has already exited. - /// - /// If the child has exited, then `Ok(Some(status))` is returned. If the - /// exit status is not available at this time then `Ok(None)` is returned. - /// If an error occurs, then that error is returned. - /// - /// Note that unlike `wait`, this function will not attempt to drop stdin. - /// - /// # Examples - /// - /// ```no_run - /// use std::process::Command; - /// - /// let mut child = Command::new("ls").spawn()?; - /// - /// match child.try_wait() { - /// Ok(Some(status)) => println!("exited with: {status}"), - /// Ok(None) => { - /// println!("status not ready yet, let's really wait"); - /// let res = child.wait(); - /// println!("result: {res:?}"); - /// } - /// Err(e) => println!("error attempting to wait: {e}"), - /// } - /// # std::io::Result::Ok(()) - /// ``` - #[stable(feature = "process_try_wait", since = "1.18.0")] - pub fn try_wait(&mut self) -> io::Result> { - Ok(self.handle.try_wait()?.map(ExitStatus)) - } - - /// Simultaneously waits for the child to exit and collect all remaining - /// output on the stdout/stderr handles, returning an `Output` - /// instance. - /// - /// The stdin handle to the child process, if any, will be closed - /// before waiting. This helps avoid deadlock: it ensures that the - /// child does not block waiting for input from the parent, while - /// the parent waits for the child to exit. - /// - /// By default, stdin, stdout and stderr are inherited from the parent. - /// In order to capture the output into this `Result` it is - /// necessary to create new pipes between parent and child. Use - /// `stdout(Stdio::piped())` or `stderr(Stdio::piped())`, respectively. - /// - /// # Examples - /// - /// ```should_panic - /// use std::process::{Command, Stdio}; - /// - /// let child = Command::new("/bin/cat") - /// .arg("file.txt") - /// .stdout(Stdio::piped()) - /// .spawn() - /// .expect("failed to execute child"); - /// - /// let output = child - /// .wait_with_output() - /// .expect("failed to wait on child"); - /// - /// assert!(output.status.success()); - /// ``` - /// - #[stable(feature = "process", since = "1.0.0")] - pub fn wait_with_output(mut self) -> io::Result { - drop(self.stdin.take()); - - let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); - match (self.stdout.take(), self.stderr.take()) { - (None, None) => {} - (Some(mut out), None) => { - let res = out.read_to_end(&mut stdout); - res.unwrap(); - } - (None, Some(mut err)) => { - let res = err.read_to_end(&mut stderr); - res.unwrap(); - } - (Some(out), Some(err)) => { - let res = imp::read_output(out.inner, &mut stdout, err.inner, &mut stderr); - res.unwrap(); - } - } - - let status = self.wait()?; - Ok(Output { status, stdout, stderr }) - } -} - -/// Terminates the current process with the specified exit code. -/// -/// This function will never return and will immediately terminate the current -/// process. The exit code is passed through to the underlying OS and will be -/// available for consumption by another process. -/// -/// Note that because this function never returns, and that it terminates the -/// process, no destructors on the current stack or any other thread's stack -/// will be run. If a clean shutdown is needed it is recommended to only call -/// this function at a known point where there are no more destructors left -/// to run; or, preferably, simply return a type implementing [`Termination`] -/// (such as [`ExitCode`] or `Result`) from the `main` function and avoid this -/// function altogether: -/// -/// ``` -/// # use std::io::Error as MyError; -/// fn main() -> Result<(), MyError> { -/// // ... -/// Ok(()) -/// } -/// ``` -/// -/// In its current implementation, this function will execute exit handlers registered with `atexit` -/// as well as other platform-specific exit handlers (e.g. `fini` sections of ELF shared objects). -/// This means that Rust requires that all exit handlers are safe to execute at any time. In -/// particular, if an exit handler cleans up some state that might be concurrently accessed by other -/// threads, it is required that the exit handler performs suitable synchronization with those -/// threads. (The alternative to this requirement would be to not run exit handlers at all, which is -/// considered undesirable. Note that returning from `main` also calls `exit`, so making `exit` an -/// unsafe operation is not an option.) -/// -/// ## Platform-specific behavior -/// -/// **Unix**: On Unix-like platforms, it is unlikely that all 32 bits of `exit` -/// will be visible to a parent process inspecting the exit code. On most -/// Unix-like platforms, only the eight least-significant bits are considered. -/// -/// For example, the exit code for this example will be `0` on Linux, but `256` -/// on Windows: -/// -/// ```no_run -/// use std::process; -/// -/// process::exit(0x0100); -/// ``` -/// -/// ### Safe interop with C code -/// -/// On Unix, this function is currently implemented using the `exit` C function [`exit`][C-exit]. As -/// of C23, the C standard does not permit multiple threads to call `exit` concurrently. Rust -/// mitigates this with a lock, but if C code calls `exit`, that can still cause undefined behavior. -/// Note that returning from `main` is equivalent to calling `exit`. -/// -/// Therefore, it is undefined behavior to have two concurrent threads perform the following -/// without synchronization: -/// - One thread calls Rust's `exit` function or returns from Rust's `main` function -/// - Another thread calls the C function `exit` or `quick_exit`, or returns from C's `main` function -/// -/// Note that if a binary contains multiple copies of the Rust runtime (e.g., when combining -/// multiple `cdylib` or `staticlib`), they each have their own separate lock, so from the -/// perspective of code running in one of the Rust runtimes, the "outside" Rust code is basically C -/// code, and concurrent `exit` again causes undefined behavior. -/// -/// Individual C implementations might provide more guarantees than the standard and permit concurrent -/// calls to `exit`; consult the documentation of your C implementation for details. -/// -/// For some of the on-going discussion to make `exit` thread-safe in C, see: -/// - [Rust issue #126600](https://github.com/rust-lang/rust/issues/126600) -/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=1845) -/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=31997) -/// -/// [C-exit]: https://en.cppreference.com/w/c/program/exit -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "process_exit")] -pub fn exit(code: i32) -> ! { - crate::rt::cleanup(); - crate::sys::exit::exit(code) -} - -/// Terminates the process in an abnormal fashion. -/// -/// The function will never return and will immediately terminate the current -/// process in a platform specific "abnormal" manner. As a consequence, -/// no destructors on the current stack or any other thread's stack -/// will be run, Rust IO buffers (eg, from `BufWriter`) will not be flushed, -/// and C stdio buffers will (on most platforms) not be flushed. -/// -/// This is in contrast to the default behavior of [`panic!`] which unwinds -/// the current thread's stack and calls all destructors. -/// When `panic="abort"` is set, either as an argument to `rustc` or in a -/// crate's Cargo.toml, [`panic!`] and `abort` are similar. However, -/// [`panic!`] will still call the [panic hook] while `abort` will not. -/// -/// If a clean shutdown is needed it is recommended to only call -/// this function at a known point where there are no more destructors left -/// to run. -/// -/// The process's termination will be similar to that from the C `abort()` -/// function. On Unix, the process will terminate with signal `SIGABRT`, which -/// typically means that the shell prints "Aborted". -/// -/// # Examples -/// -/// ```no_run -/// use std::process; -/// -/// fn main() { -/// println!("aborting"); -/// -/// process::abort(); -/// -/// // execution never gets here -/// } -/// ``` -/// -/// The `abort` function terminates the process, so the destructor will not -/// get run on the example below: -/// -/// ```no_run -/// use std::process; -/// -/// struct HasDrop; -/// -/// impl Drop for HasDrop { -/// fn drop(&mut self) { -/// println!("This will never be printed!"); -/// } -/// } -/// -/// fn main() { -/// let _x = HasDrop; -/// process::abort(); -/// // the destructor implemented for HasDrop will never get run -/// } -/// ``` -/// -/// [panic hook]: crate::panic::set_hook -#[stable(feature = "process_abort", since = "1.17.0")] -#[cold] -#[cfg_attr(not(test), rustc_diagnostic_item = "process_abort")] -#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -pub fn abort() -> ! { - crate::sys::abort_internal(); -} - -/// Returns the OS-assigned process identifier associated with this process. -/// -/// # Examples -/// -/// ```no_run -/// use std::process; -/// -/// println!("My pid is {}", process::id()); -/// ``` -#[must_use] -#[stable(feature = "getpid", since = "1.26.0")] -pub fn id() -> u32 { - imp::getpid() -} - -/// A trait for implementing arbitrary return types in the `main` function. -/// -/// The C-main function only supports returning integers. -/// So, every type implementing the `Termination` trait has to be converted -/// to an integer. -/// -/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate -/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. -/// -/// Because different runtimes have different specifications on the return value -/// of the `main` function, this trait is likely to be available only on -/// standard library's runtime for convenience. Other runtimes are not required -/// to provide similar functionality. -#[cfg_attr(not(any(test, doctest)), lang = "termination")] -#[stable(feature = "termination_trait_lib", since = "1.61.0")] -#[rustc_on_unimplemented(on( - cause = "MainFunctionType", - message = "`main` has invalid return type `{Self}`", - label = "`main` can only return types that implement `{This}`" -))] -pub trait Termination { - /// Is called to get the representation of the value as status code. - /// This status code is returned to the operating system. - #[stable(feature = "termination_trait_lib", since = "1.61.0")] - fn report(self) -> ExitCode; -} - -#[stable(feature = "termination_trait_lib", since = "1.61.0")] -impl Termination for () { - #[inline] - fn report(self) -> ExitCode { - ExitCode::SUCCESS - } -} - -#[stable(feature = "termination_trait_lib", since = "1.61.0")] -impl Termination for ! { - fn report(self) -> ExitCode { - self - } -} - -#[stable(feature = "termination_trait_lib", since = "1.61.0")] -impl Termination for Infallible { - fn report(self) -> ExitCode { - match self {} - } -} - -#[stable(feature = "termination_trait_lib", since = "1.61.0")] -impl Termination for ExitCode { - #[inline] - fn report(self) -> ExitCode { - self - } -} - -#[stable(feature = "termination_trait_lib", since = "1.61.0")] -impl Termination for Result { - fn report(self) -> ExitCode { - match self { - Ok(val) => val.report(), - Err(err) => { - io::attempt_print_to_stderr(format_args_nl!("Error: {err:?}")); - ExitCode::FAILURE - } - } - } -} diff --git a/library/std/src/process.rs b/library/std/src/process.rs new file mode 120000 index 0000000..565177b --- /dev/null +++ b/library/std/src/process.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/process.rs \ No newline at end of file diff --git a/library/std/src/random.rs b/library/std/src/random.rs deleted file mode 100644 index a18dcf9..0000000 --- a/library/std/src/random.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Random value generation. - -#[unstable(feature = "random", issue = "130703")] -pub use core::random::*; - -use crate::sys::random as sys; - -/// The default random source. -/// -/// This asks the system for random data suitable for cryptographic purposes -/// such as key generation. If security is a concern, consult the platform -/// documentation below for the specific guarantees your target provides. -/// -/// The high quality of randomness provided by this source means it can be quite -/// slow on some targets. If you need a large quantity of random numbers and -/// security is not a concern, consider using an alternative random number -/// generator (potentially seeded from this one). -/// -/// # Underlying sources -/// -/// Platform | Source -/// -----------------------|--------------------------------------------------------------- -/// Linux | [`getrandom`] or [`/dev/urandom`] after polling `/dev/random` -/// Windows | [`ProcessPrng`](https://learn.microsoft.com/en-us/windows/win32/seccng/processprng) -/// Apple | `CCRandomGenerateBytes` -/// DragonFly | [`arc4random_buf`](https://man.dragonflybsd.org/?command=arc4random) -/// ESP-IDF | [`esp_fill_random`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t) -/// FreeBSD | [`arc4random_buf`](https://man.freebsd.org/cgi/man.cgi?query=arc4random) -/// Fuchsia | [`cprng_draw`](https://fuchsia.dev/reference/syscalls/cprng_draw) -/// Haiku | `arc4random_buf` -/// Illumos | [`arc4random_buf`](https://www.illumos.org/man/3C/arc4random) -/// NetBSD | [`arc4random_buf`](https://man.netbsd.org/arc4random.3) -/// OpenBSD | [`arc4random_buf`](https://man.openbsd.org/arc4random.3) -/// Solaris | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html) -/// Vita | `arc4random_buf` -/// Hermit | `read_entropy` -/// Horizon, Cygwin | `getrandom` -/// AIX, Hurd, L4Re, QNX | `/dev/urandom` -/// Redox | `/scheme/rand` -/// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/main/bsp-howto/getentropy.html) -/// SGX | [`rdrand`](https://en.wikipedia.org/wiki/RDRAND) -/// SOLID | `SOLID_RNG_SampleRandomBytes` -/// TEEOS | `TEE_GenerateRandom` -/// UEFI | [`EFI_RNG_PROTOCOL`](https://uefi.org/specs/UEFI/2.10/37_Secure_Technologies.html#random-number-generator-protocol) -/// VxWorks | `randABytes` after waiting for `randSecure` to become ready -/// WASI | [`random_get`](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-random_getbuf-pointeru8-buf_len-size---result-errno) -/// ZKVM | `sys_rand` -/// -/// Note that the sources used might change over time. -/// -/// Consult the documentation for the underlying operations on your supported -/// targets to determine whether they provide any particular desired properties, -/// such as support for reseeding on VM fork operations. -/// -/// [`getrandom`]: https://www.man7.org/linux/man-pages/man2/getrandom.2.html -/// [`/dev/urandom`]: https://www.man7.org/linux/man-pages/man4/random.4.html -#[derive(Default, Debug, Clone, Copy)] -#[unstable(feature = "random", issue = "130703")] -pub struct DefaultRandomSource; - -#[unstable(feature = "random", issue = "130703")] -impl RandomSource for DefaultRandomSource { - fn fill_bytes(&mut self, bytes: &mut [u8]) { - sys::fill_bytes(bytes) - } -} - -/// Generates a random value from a distribution, using the default random source. -/// -/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and will sample -/// according to the same distribution as the underlying [`Distribution`] trait implementation. See -/// [`DefaultRandomSource`] for more information about how randomness is sourced. -/// -/// # Examples -/// -/// Generating a [version 4/variant 1 UUID] represented as text: -/// ``` -/// #![feature(random)] -/// -/// use std::random::random; -/// -/// let bits: u128 = random(..); -/// let g1 = (bits >> 96) as u32; -/// let g2 = (bits >> 80) as u16; -/// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16; -/// let g4 = (0x8000 | (bits >> 48) & 0x3fff) as u16; -/// let g5 = (bits & 0xffffffffffff) as u64; -/// let uuid = format!("{g1:08x}-{g2:04x}-{g3:04x}-{g4:04x}-{g5:012x}"); -/// println!("{uuid}"); -/// ``` -/// -/// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) -#[unstable(feature = "random", issue = "130703")] -pub fn random(dist: impl Distribution) -> T { - dist.sample(&mut DefaultRandomSource) -} diff --git a/library/std/src/random.rs b/library/std/src/random.rs new file mode 120000 index 0000000..587ed19 --- /dev/null +++ b/library/std/src/random.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/random.rs \ No newline at end of file diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs deleted file mode 100644 index 1e7de69..0000000 --- a/library/std/src/rt.rs +++ /dev/null @@ -1,211 +0,0 @@ -//! 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(); -} - -// Prints to the "panic output", depending on the platform this may be: -// - the standard error output -// - some dedicated platform specific output -// - nothing (so this macro is a no-op) -macro_rules! rtprintpanic { - ($($t:tt)*) => { - #[cfg(not(panic = "immediate-abort"))] - if let Some(mut out) = crate::sys::stdio::panic_output() { - let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); - } - #[cfg(panic = "immediate-abort")] - { - let _ = format_args!($($t)*); - } - } -} - -macro_rules! rtabort { - ($($t:tt)*) => { - { - rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*)); - crate::process::abort(); - } - } -} - -macro_rules! rtassert { - ($e:expr) => { - if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))); - } - }; -} - -macro_rules! rtunwrap { - ($ok:ident, $e:expr) => { - match $e { - $ok(v) => v, - ref err => { - let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug - rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) - } - } - }; -} - -fn handle_rt_panic(e: Box) -> T { - mem::forget(e); - rtabort!("initialization or cleanup bug"); -} - -// One-time runtime initialization. -// Runs before `main`. -// SAFETY: must be called only once during runtime initialization. -// NOTE: this is not guaranteed to run, for example when Rust code is called externally. -// -// # The `sigpipe` parameter -// -// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to -// `SIG_IGN`. Applications have good reasons to want a different behavior -// though, so there is a `-Zon-broken-pipe` compiler flag that -// can be used to select how `SIGPIPE` shall be setup (if changed at all) before -// `fn main()` is called. See -// for more info. -// -// The `sigpipe` parameter to this function gets its value via the code that -// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for -// all platforms and not only Unix, is because std is not allowed to have `cfg` -// directives as this high level. See the module docs in -// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe` -// has a value, but its value is ignored. -// -// Even though it is an `u8`, it only ever has 4 values. These are documented in -// `compiler/rustc_session/src/config/sigpipe.rs`. -#[cfg_attr(test, allow(dead_code))] -unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { - // Remember the main thread ID to give it the correct name. - // SAFETY: this is the only time and place where we call this function. - unsafe { main_thread::set(thread::current_id()) }; - - #[cfg_attr(target_os = "teeos", allow(unused_unsafe))] - unsafe { - sys::init(argc, argv, sigpipe) - }; -} - -/// Clean up the thread-local runtime state. This *should* be run after all other -/// code managed by the Rust runtime, but will not cause UB if that condition is -/// not fulfilled. Also note that this function is not guaranteed to be run, but -/// skipping it will cause leaks and therefore is to be avoided. -pub(crate) fn thread_cleanup() { - // This function is run in situations where unwinding leads to an abort - // (think `extern "C"` functions). Abort here instead so that we can - // print a nice message. - panic::catch_unwind(|| { - crate::thread::drop_current(); - }) - .unwrap_or_else(handle_rt_panic); -} - -// One-time runtime cleanup. -// Runs after `main` or at program exit. -// NOTE: this is not guaranteed to run, for example when the program aborts. -pub(crate) fn cleanup() { - static CLEANUP: Once = Once::new(); - CLEANUP.call_once(|| unsafe { - // Flush stdout and disable buffering. - crate::io::cleanup(); - // SAFETY: Only called once during runtime cleanup. - sys::cleanup(); - }); -} - -// To reduce the generated code of the new `lang_start`, this function is doing -// the real work. -#[cfg(not(test))] -fn lang_start_internal( - main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), - argc: isize, - argv: *const *const u8, - sigpipe: u8, -) -> isize { - // Guard against the code called by this function from unwinding outside of the Rust-controlled - // code, which is UB. This is a requirement imposed by a combination of how the - // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking - // mechanism itself. - // - // There are a couple of instances where unwinding can begin. First is inside of the - // `rt::init`, `rt::cleanup` and similar functions controlled by std. In those instances a - // panic is a std implementation bug. A quite likely one too, as there isn't any way to - // prevent std from accidentally introducing a panic to these functions. Another is from - // user code from `main` or, more nefariously, as described in e.g. issue #86030. - // - // We use `catch_unwind` with `handle_rt_panic` instead of `abort_unwind` to make the error in - // case of a panic a bit nicer. - panic::catch_unwind(move || { - // SAFETY: Only called once during runtime initialization. - unsafe { init(argc, argv, sigpipe) }; - - let ret_code = panic::catch_unwind(main).unwrap_or_else(move |payload| { - // Carefully dispose of the panic payload. - let payload = panic::AssertUnwindSafe(payload); - panic::catch_unwind(move || drop({ payload }.0)).unwrap_or_else(move |e| { - mem::forget(e); // do *not* drop the 2nd payload - rtabort!("drop of the panic payload panicked"); - }); - // Return error code for panicking programs. - 101 - }); - let ret_code = ret_code as isize; - - cleanup(); - // Guard against multiple threads calling `libc::exit` concurrently. - // See the documentation for `unique_thread_exit` for more information. - crate::sys::exit::unique_thread_exit(); - - ret_code - }) - .unwrap_or_else(handle_rt_panic) -} - -#[cfg(not(any(test, doctest)))] -#[lang = "start"] -fn lang_start( - main: fn() -> T, - argc: isize, - argv: *const *const u8, - sigpipe: u8, -) -> isize { - lang_start_internal( - &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), - argc, - argv, - sigpipe, - ) -} diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs new file mode 120000 index 0000000..9952d3c --- /dev/null +++ b/library/std/src/rt.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs \ No newline at end of file diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs deleted file mode 100644 index ecffc6d..0000000 --- a/library/std/src/sys/args/unsupported.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; - -pub struct Args {} - -pub fn args() -> Args { - Args {} -} - -impl fmt::Debug for Args { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().finish() - } -} - -impl Iterator for Args { - type Item = OsString; - - #[inline] - fn next(&mut self) -> Option { - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) - } -} - -impl DoubleEndedIterator for Args { - #[inline] - fn next_back(&mut self) -> Option { - None - } -} - -impl ExactSizeIterator for Args { - #[inline] - fn len(&self) -> usize { - 0 - } -} diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs new file mode 120000 index 0000000..3684428 --- /dev/null +++ b/library/std/src/sys/args/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/args/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs deleted file mode 100644 index 858a958..0000000 --- a/library/std/src/sys/backtrace.rs +++ /dev/null @@ -1,238 +0,0 @@ -//! Common code for printing backtraces. -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; -use crate::borrow::Cow; -use crate::io::prelude::*; -use crate::path::{self, Path, PathBuf}; -use crate::sync::{Mutex, MutexGuard, PoisonError}; -use crate::{env, fmt, io}; - -/// Max number of frames to print. -const MAX_NB_FRAMES: usize = 100; - -pub(crate) const FULL_BACKTRACE_DEFAULT: bool = cfg_select! { - // Fuchsia components default to full backtrace. - target_os = "fuchsia" => true, - _ => false, -}; - -pub(crate) struct BacktraceLock<'a>(#[allow(dead_code)] MutexGuard<'a, ()>); - -pub(crate) fn lock<'a>() -> BacktraceLock<'a> { - static LOCK: Mutex<()> = Mutex::new(()); - BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner)) -} - -impl BacktraceLock<'_> { - /// Prints the current backtrace. - pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { - // There are issues currently linking libbacktrace into tests, and in - // general during std's own unit tests we're not testing this path. In - // test mode immediately return here to optimize away any references to the - // libbacktrace symbols - if cfg!(test) { - return Ok(()); - } - - struct DisplayBacktrace { - format: PrintFmt, - } - impl fmt::Display for DisplayBacktrace { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - // SAFETY: the backtrace lock is held - unsafe { _print_fmt(fmt, self.format) } - } - } - write!(w, "{}", DisplayBacktrace { format }) - } -} - -/// # Safety -/// -/// This function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program. -unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { - // Always 'fail' to get the cwd when running under Miri - - // this allows Miri to display backtraces in isolation mode - let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None }; - - let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { - output_filename(fmt, bows, print_fmt, cwd.as_ref()) - }; - writeln!(fmt, "stack backtrace:")?; - let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); - bt_fmt.add_context()?; - let mut idx = 0; - let mut res = Ok(()); - let mut omitted_count: usize = 0; - let mut first_omit = true; - // If we're using a short backtrace, ignore all frames until we're told to start printing. - let mut print = print_fmt != PrintFmt::Short; - set_image_base(); - // SAFETY: we roll our own locking in this town - unsafe { - backtrace_rs::trace_unsynchronized(|frame| { - if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { - return false; - } - - if cfg!(feature = "backtrace-trace-only") { - const HEX_WIDTH: usize = 2 + 2 * size_of::(); - let frame_ip = frame.ip(); - res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); - } else { - let mut hit = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; - - // `__rust_end_short_backtrace` means we are done hiding symbols - // for now. Print until we see `__rust_begin_short_backtrace`. - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_end_short_backtrace") { - print = true; - return; - } - if print && sym.contains("__rust_begin_short_backtrace") { - print = false; - return; - } - if !print { - omitted_count += 1; - } - } - } - - if print { - if omitted_count > 0 { - debug_assert!(print_fmt == PrintFmt::Short); - // only print the message between the middle of frames - if !first_omit { - let _ = writeln!( - bt_fmt.formatter(), - " [... omitted {} frame{} ...]", - omitted_count, - if omitted_count > 1 { "s" } else { "" } - ); - } - first_omit = false; - omitted_count = 0; - } - res = bt_fmt.frame().symbol(frame, symbol); - } - }); - #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))] - if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { - if !hit && print { - use crate::backtrace_rs::SymbolName; - res = bt_fmt.frame().print_raw( - frame.ip(), - Some(SymbolName::new("__my_thread_exit".as_bytes())), - None, - None, - ); - } - return false; - } - if !hit && print { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); - } - } - - idx += 1; - res.is_ok() - }) - }; - res?; - bt_fmt.finish()?; - if print_fmt == PrintFmt::Short { - writeln!( - fmt, - "note: Some details are omitted, \ - run with `RUST_BACKTRACE=full` for a verbose backtrace." - )?; - } - Ok(()) -} - -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that -/// this is only inline(never) when backtraces in std are enabled, otherwise -/// it's fine to optimize away. -#[cfg_attr(feature = "backtrace", inline(never))] -pub fn __rust_begin_short_backtrace(f: F) -> T -where - F: FnOnce() -> T, -{ - let result = f(); - - // prevent this frame from being tail-call optimised away - crate::hint::black_box(()); - - result -} - -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that -/// this is only inline(never) when backtraces in std are enabled, otherwise -/// it's fine to optimize away. -#[cfg_attr(feature = "backtrace", inline(never))] -pub fn __rust_end_short_backtrace(f: F) -> T -where - F: FnOnce() -> T, -{ - let result = f(); - - // prevent this frame from being tail-call optimised away - crate::hint::black_box(()); - - result -} - -/// Prints the filename of the backtrace frame. -/// -/// See also `output`. -pub fn output_filename( - fmt: &mut fmt::Formatter<'_>, - bows: BytesOrWideString<'_>, - print_fmt: PrintFmt, - cwd: Option<&PathBuf>, -) -> fmt::Result { - let file: Cow<'_, Path> = match bows { - #[cfg(unix)] - BytesOrWideString::Bytes(bytes) => { - use crate::os::unix::prelude::*; - Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() - } - #[cfg(not(unix))] - BytesOrWideString::Bytes(bytes) => { - Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() - } - #[cfg(windows)] - BytesOrWideString::Wide(wide) => { - use crate::os::windows::prelude::*; - Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) - } - #[cfg(not(windows))] - BytesOrWideString::Wide(_wide) => Path::new("").into(), - }; - if print_fmt == PrintFmt::Short && file.is_absolute() { - if let Some(cwd) = cwd { - if let Ok(stripped) = file.strip_prefix(&cwd) { - if let Some(s) = stripped.to_str() { - return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); - } - } - } - } - fmt::Display::fmt(&file.display(), fmt) -} - -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -pub fn set_image_base() { - let image_base = crate::os::fortanix_sgx::mem::image_base(); - backtrace_rs::set_image_base(crate::ptr::without_provenance_mut(image_base as _)); -} - -#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))] -pub fn set_image_base() { - // nothing to do for platforms other than SGX -} diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs new file mode 120000 index 0000000..fadb383 --- /dev/null +++ b/library/std/src/sys/backtrace.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs \ No newline at end of file diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs deleted file mode 100644 index 1592218..0000000 --- a/library/std/src/sys/cmath.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![cfg(not(test))] - -// These symbols are all defined by `libm`, -// or by `compiler-builtins` on unsupported platforms. -unsafe extern "C" { - pub safe fn acos(n: f64) -> f64; - pub safe fn asin(n: f64) -> f64; - pub safe fn atan(n: f64) -> f64; - pub safe fn atan2(a: f64, b: f64) -> f64; - pub safe fn cosh(n: f64) -> f64; - pub safe fn expm1(n: f64) -> f64; - pub safe fn expm1f(n: f32) -> f32; - #[cfg_attr(target_env = "msvc", link_name = "_hypot")] - pub safe fn hypot(x: f64, y: f64) -> f64; - #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] - pub safe fn hypotf(x: f32, y: f32) -> f32; - pub safe fn log1p(n: f64) -> f64; - pub safe fn log1pf(n: f32) -> f32; - pub safe fn sinh(n: f64) -> f64; - pub safe fn tan(n: f64) -> f64; - pub safe fn tanh(n: f64) -> f64; - pub safe fn tgamma(n: f64) -> f64; - pub safe fn tgammaf(n: f32) -> f32; - pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64; - #[cfg(not(target_os = "aix"))] - pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32; - pub safe fn erf(n: f64) -> f64; - pub safe fn erff(n: f32) -> f32; - pub safe fn erfc(n: f64) -> f64; - pub safe fn erfcf(n: f32) -> f32; - - pub safe fn acosf128(n: f128) -> f128; - pub safe fn asinf128(n: f128) -> f128; - pub safe fn atanf128(n: f128) -> f128; - pub safe fn atan2f128(a: f128, b: f128) -> f128; - pub safe fn cbrtf128(n: f128) -> f128; - pub safe fn coshf128(n: f128) -> f128; - pub safe fn expm1f128(n: f128) -> f128; - pub safe fn hypotf128(x: f128, y: f128) -> f128; - pub safe fn log1pf128(n: f128) -> f128; - pub safe fn sinhf128(n: f128) -> f128; - pub safe fn tanf128(n: f128) -> f128; - pub safe fn tanhf128(n: f128) -> f128; - pub safe fn tgammaf128(n: f128) -> f128; - pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128; - pub safe fn erff128(n: f128) -> f128; - pub safe fn erfcf128(n: f128) -> f128; -} - -cfg_select! { - all(target_os = "windows", target_env = "msvc", target_arch = "x86") => { - // On 32-bit x86 MSVC these functions aren't defined, so we just define shims - // which promote everything to f64, perform the calculation, and then demote - // back to f32. While not precisely correct should be "correct enough" for now. - #[inline] - pub fn acosf(n: f32) -> f32 { - f64::acos(n as f64) as f32 - } - - #[inline] - pub fn asinf(n: f32) -> f32 { - f64::asin(n as f64) as f32 - } - - #[inline] - pub fn atan2f(n: f32, b: f32) -> f32 { - f64::atan2(n as f64, b as f64) as f32 - } - - #[inline] - pub fn atanf(n: f32) -> f32 { - f64::atan(n as f64) as f32 - } - - #[inline] - pub fn coshf(n: f32) -> f32 { - f64::cosh(n as f64) as f32 - } - - #[inline] - pub fn sinhf(n: f32) -> f32 { - f64::sinh(n as f64) as f32 - } - - #[inline] - pub fn tanf(n: f32) -> f32 { - f64::tan(n as f64) as f32 - } - - #[inline] - pub fn tanhf(n: f32) -> f32 { - f64::tanh(n as f64) as f32 - } - } - _ => { - unsafe extern "C" { - pub safe fn acosf(n: f32) -> f32; - pub safe fn asinf(n: f32) -> f32; - pub safe fn atan2f(a: f32, b: f32) -> f32; - pub safe fn atanf(n: f32) -> f32; - pub safe fn coshf(n: f32) -> f32; - pub safe fn sinhf(n: f32) -> f32; - pub safe fn tanf(n: f32) -> f32; - pub safe fn tanhf(n: f32) -> f32; - } - } -} - -// On AIX, we don't have lgammaf_r only the f64 version, so we can -// use the f64 version lgamma_r -#[cfg(target_os = "aix")] -pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 { - lgamma_r(n.into(), s) as f32 -} diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs new file mode 120000 index 0000000..3236110 --- /dev/null +++ b/library/std/src/sys/cmath.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/cmath.rs \ No newline at end of file diff --git a/library/std/src/sys/configure_builtins.rs b/library/std/src/sys/configure_builtins.rs deleted file mode 100644 index 7cdf04e..0000000 --- a/library/std/src/sys/configure_builtins.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! The configure builtins provides runtime support compiler-builtin features -//! which require dynamic initialization to work as expected, e.g. aarch64 -//! outline-atomics. - -/// Enable LSE atomic operations at startup, if supported. -/// -/// Linker sections are based on what [`ctor`] does, with priorities to run slightly before user -/// code: -/// -/// - Apple uses the section `__mod_init_func`, `mod_init_funcs` is needed to set -/// `S_MOD_INIT_FUNC_POINTERS`. There doesn't seem to be a way to indicate priorities. -/// - Windows uses `.CRT$XCT`, which is run before user constructors (these should use `.CRT$XCU`). -/// - ELF uses `.init_array` with a priority of 90, which runs before our `ARGV_INIT_ARRAY` -/// initializer (priority 99). Both are within the 0-100 implementation-reserved range, per docs -/// for the [`prio-ctor-dtor`] warning, and this matches compiler-rt's `CONSTRUCTOR_PRIORITY`. -/// -/// To save startup time, the initializer is only run if outline atomic routines from -/// compiler-builtins may be used. If LSE is known to be available then the calls are never -/// emitted, and if we build the C intrinsics then it has its own initializer using the symbol -/// `__aarch64_have_lse_atomics`. -/// -/// Initialization is done in a global constructor to so we get the same behavior regardless of -/// whether Rust's `init` is used, or if we are in a `dylib` or `no_main` situation (as opposed -/// to doing it as part of pre-main startup). This also matches C implementations. -/// -/// Ideally `core` would have something similar, but detecting the CPU features requires the -/// auxiliary vector from the OS. We do the initialization in `std` rather than as part of -/// `compiler-builtins` because a builtins->std dependency isn't possible, and inlining parts of -/// `std-detect` would be much messier. -/// -/// [`ctor`]: https://github.com/mmastrac/rust-ctor/blob/63382b833ddcbfb8b064f4e86bfa1ed4026ff356/shared/src/macros/mod.rs#L522-L534 -/// [`prio-ctor-dtor`]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html -#[cfg(all( - target_arch = "aarch64", - target_feature = "outline-atomics", - not(target_feature = "lse"), - not(feature = "compiler-builtins-c"), -))] -#[used] -#[cfg_attr(target_vendor = "apple", unsafe(link_section = "__DATA,__mod_init_func,mod_init_funcs"))] -#[cfg_attr(target_os = "windows", unsafe(link_section = ".CRT$XCT"))] -#[cfg_attr( - not(any(target_vendor = "apple", target_os = "windows")), - unsafe(link_section = ".init_array.90") -)] -static RUST_LSE_INIT: extern "C" fn() = { - extern "C" fn init_lse() { - use crate::arch; - - // This is provided by compiler-builtins::aarch64_outline_atomics. - unsafe extern "C" { - fn __rust_enable_lse(); - } - - if arch::is_aarch64_feature_detected!("lse") { - unsafe { - __rust_enable_lse(); - } - } - } - init_lse -}; diff --git a/library/std/src/sys/configure_builtins.rs b/library/std/src/sys/configure_builtins.rs new file mode 120000 index 0000000..81694b4 --- /dev/null +++ b/library/std/src/sys/configure_builtins.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/configure_builtins.rs \ No newline at end of file diff --git a/library/std/src/sys/env/common.rs b/library/std/src/sys/env/common.rs deleted file mode 100644 index 87e86e2..0000000 --- a/library/std/src/sys/env/common.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::ffi::OsString; -use crate::{fmt, vec}; - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -impl Env { - pub(super) fn new(env: Vec<(OsString, OsString)>) -> Self { - Env { iter: env.into_iter() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} diff --git a/library/std/src/sys/env/common.rs b/library/std/src/sys/env/common.rs new file mode 120000 index 0000000..6371ec4 --- /dev/null +++ b/library/std/src/sys/env/common.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/env/common.rs \ No newline at end of file diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs deleted file mode 100644 index 8985651..0000000 --- a/library/std/src/sys/env/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Platform-dependent environment variables abstraction. - -#![forbid(unsafe_op_in_unsafe_fn)] - -#[cfg(any( - target_family = "unix", - target_os = "hermit", - target_os = "motor", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "solid_asp3", - target_os = "uefi", - target_os = "wasi", - target_os = "xous", -))] -mod common; - -cfg_select! { - target_family = "unix" => { - mod unix; - pub use unix::*; - } - target_family = "windows" => { - mod windows; - pub use windows::*; - } - target_os = "hermit" => { - mod hermit; - pub use hermit::*; - } - target_os = "motor" => { - mod motor; - pub use motor::*; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::*; - } - target_os = "solid_asp3" => { - mod solid; - pub use solid::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - target_os = "wasi" => { - mod wasi; - pub use wasi::*; - } - target_os = "xous" => { - mod xous; - pub use xous::*; - } - target_os = "zkvm" => { - mod zkvm; - pub use zkvm::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } -} diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs new file mode 120000 index 0000000..485c964 --- /dev/null +++ b/library/std/src/sys/env/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/env/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/env/unsupported.rs b/library/std/src/sys/env/unsupported.rs deleted file mode 100644 index a967ace..0000000 --- a/library/std/src/sys/env/unsupported.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::ffi::{OsStr, OsString}; -use crate::{fmt, io}; - -pub struct Env(!); - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0 - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -pub fn getenv(_: &OsStr) -> Option { - None -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} diff --git a/library/std/src/sys/env/unsupported.rs b/library/std/src/sys/env/unsupported.rs new file mode 120000 index 0000000..fd89779 --- /dev/null +++ b/library/std/src/sys/env/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/env/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs deleted file mode 100644 index 573f540..0000000 --- a/library/std/src/sys/env_consts.rs +++ /dev/null @@ -1,426 +0,0 @@ -//! Constants associated with each target. - -// Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates. -// This ensures that they must be mutually exclusive and do not have precedence -// like cfg_select!. -macro cfg_unordered( - $(#[cfg($cfg:meta)] $os:item)* - #[else] $fallback:item -) { - $(#[cfg($cfg)] $os)* - #[cfg(not(any($($cfg),*)))] $fallback -} - -// Keep entries sorted alphabetically and mutually exclusive. - -cfg_unordered! { - -#[cfg(target_os = "aix")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "aix"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".a"; - pub const DLL_EXTENSION: &str = "a"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "android")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "android"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "cygwin")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "cygwin"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".dll"; - pub const DLL_EXTENSION: &str = "dll"; - pub const EXE_SUFFIX: &str = ".exe"; - pub const EXE_EXTENSION: &str = "exe"; -} - -#[cfg(target_os = "dragonfly")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "dragonfly"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "emscripten")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "emscripten"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ".js"; - pub const EXE_EXTENSION: &str = "js"; -} - -#[cfg(target_os = "espidf")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "espidf"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "freebsd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "freebsd"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "fuchsia")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "fuchsia"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "haiku")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "haiku"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "hermit")] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = "hermit"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "horizon")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "horizon"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ".elf"; - pub const EXE_EXTENSION: &str = "elf"; -} - -#[cfg(target_os = "hurd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "hurd"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "illumos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "illumos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "ios")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "ios"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "l4re")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "l4re"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "linux")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "linux"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "macos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "macos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "netbsd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "netbsd"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "nto")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "nto"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "nuttx")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "nuttx"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "openbsd")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "openbsd"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "redox")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "redox"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "rtems")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "rtems"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".sgxs"; - pub const DLL_EXTENSION: &str = "sgxs"; - pub const EXE_SUFFIX: &str = ".sgxs"; - pub const EXE_EXTENSION: &str = "sgxs"; -} - -#[cfg(target_os = "solaris")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "solaris"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "solid_asp3")] -pub mod os { - pub const FAMILY: &str = "itron"; - pub const OS: &str = "solid"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "tvos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "tvos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "uefi")] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = "uefi"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ".efi"; - pub const EXE_EXTENSION: &str = "efi"; -} - -#[cfg(target_os = "vexos")] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = "vexos"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ".bin"; - pub const EXE_EXTENSION: &str = "bin"; -} - -#[cfg(target_os = "visionos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "visionos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "vita")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "vita"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ".elf"; - pub const EXE_EXTENSION: &str = "elf"; -} - -#[cfg(target_os = "vxworks")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "vxworks"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(all(target_family = "wasm", not(any(target_os = "emscripten", target_os = "linux"))))] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".wasm"; - pub const DLL_EXTENSION: &str = "wasm"; - pub const EXE_SUFFIX: &str = ".wasm"; - pub const EXE_EXTENSION: &str = "wasm"; -} - -#[cfg(target_os = "watchos")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "watchos"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".dylib"; - pub const DLL_EXTENSION: &str = "dylib"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -#[cfg(target_os = "windows")] -pub mod os { - pub const FAMILY: &str = "windows"; - pub const OS: &str = "windows"; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".dll"; - pub const DLL_EXTENSION: &str = "dll"; - pub const EXE_SUFFIX: &str = ".exe"; - pub const EXE_EXTENSION: &str = "exe"; -} - -#[cfg(target_os = "zkvm")] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ".elf"; - pub const DLL_EXTENSION: &str = "elf"; - pub const EXE_SUFFIX: &str = ".elf"; - pub const EXE_EXTENSION: &str = "elf"; -} - -// The fallback when none of the other gates match. -#[else] -pub mod os { - pub const FAMILY: &str = ""; - pub const OS: &str = ""; - pub const DLL_PREFIX: &str = ""; - pub const DLL_SUFFIX: &str = ""; - pub const DLL_EXTENSION: &str = ""; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - -} diff --git a/library/std/src/sys/env_consts.rs b/library/std/src/sys/env_consts.rs new file mode 120000 index 0000000..621fc16 --- /dev/null +++ b/library/std/src/sys/env_consts.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/env_consts.rs \ No newline at end of file diff --git a/library/std/src/sys/exit.rs b/library/std/src/sys/exit.rs deleted file mode 100644 index 53fb92b..0000000 --- a/library/std/src/sys/exit.rs +++ /dev/null @@ -1,143 +0,0 @@ -cfg_select! { - target_os = "linux" => { - /// Mitigation for - /// - /// On glibc, `libc::exit` has been observed to not always be thread-safe. - /// It is currently unclear whether that is a glibc bug or allowed by the standard. - /// To mitigate this problem, we ensure that only one - /// Rust thread calls `libc::exit` (or returns from `main`) by calling this function before - /// calling `libc::exit` (or returning from `main`). - /// - /// Technically, this is not enough to ensure soundness, since other code directly calling - /// `libc::exit` will still race with this. - /// - /// *This function does not itself call `libc::exit`.* This is so it can also be used - /// to guard returning from `main`. - /// - /// This function will return only the first time it is called in a process. - /// - /// * If it is called again on the same thread as the first call, it will abort. - /// * If it is called again on a different thread, it will wait in a loop - /// (waiting for the process to exit). - pub fn unique_thread_exit() { - use crate::ffi::c_int; - use crate::ptr; - use crate::sync::atomic::AtomicPtr; - use crate::sync::atomic::Ordering::{Acquire, Relaxed}; - - static EXITING_THREAD_ID: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - - // We use the address of `errno` as a cheap and safe way to identify - // threads. As the C standard mandates that `errno` must have thread - // storage duration, we can rely on its address not changing over the - // lifetime of the thread. Additionally, accesses to `errno` are - // async-signal-safe, so this function is available in all imaginable - // circumstances. - let this_thread_id = crate::sys::io::errno_location(); - match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { - Ok(_) => { - // This is the first thread to call `unique_thread_exit`, - // and this is the first time it is called. Continue exiting. - } - Err(exiting_thread_id) if exiting_thread_id == this_thread_id => { - // This is the first thread to call `unique_thread_exit`, - // but this is the second time it is called. - // Abort the process. - core::panicking::panic_nounwind("std::process::exit called re-entrantly") - } - Err(_) => { - // This is not the first thread to call `unique_thread_exit`. - // Pause until the process exits. - loop { - // Safety: libc::pause is safe to call. - unsafe { libc::pause(); } - } - } - } - } - } - _ => { - /// Mitigation for - /// - /// Mitigation is ***NOT*** implemented on this platform, either because this platform - /// is not affected, or because mitigation is not yet implemented for this platform. - #[cfg_attr(any(test, doctest), expect(dead_code))] - pub fn unique_thread_exit() { - // Mitigation not required on platforms where `exit` is thread-safe. - } - } -} - -pub fn exit(code: i32) -> ! { - cfg_select! { - target_os = "hermit" => { - unsafe { hermit_abi::exit(code) } - } - target_os = "linux" => { - unsafe { - unique_thread_exit(); - libc::exit(code) - } - } - target_os = "motor" => { - moto_rt::process::exit(code) - } - all(target_vendor = "fortanix", target_env = "sgx") => { - crate::sys::pal::abi::exit_with_code(code as _) - } - target_os = "solid_asp3" => { - rtabort!("exit({}) called", code) - } - target_os = "teeos" => { - let _ = code; - panic!("TA should not call `exit`") - } - target_os = "uefi" => { - use r_efi::base::Status; - - use crate::os::uefi::env; - - if let (Some(boot_services), Some(handle)) = - (env::boot_services(), env::try_image_handle()) - { - let boot_services = boot_services.cast::(); - let _ = unsafe { - ((*boot_services.as_ptr()).exit)( - handle.as_ptr(), - Status::from_usize(code as usize), - 0, - crate::ptr::null_mut(), - ) - }; - } - crate::intrinsics::abort() - } - any( - target_family = "unix", - target_os = "wasi", - ) => { - unsafe { libc::exit(code as crate::ffi::c_int) } - } - target_os = "vexos" => { - let _ = code; - - unsafe { - vex_sdk::vexSystemExitRequest(); - - loop { - vex_sdk::vexTasksRun(); - } - } - } - target_os = "windows" => { - unsafe { crate::sys::pal::c::ExitProcess(code as u32) } - } - target_os = "xous" => { - crate::os::xous::ffi::exit(code as u32) - } - _ => { - let _ = code; - crate::intrinsics::abort() - } - } -} diff --git a/library/std/src/sys/exit.rs b/library/std/src/sys/exit.rs new file mode 120000 index 0000000..e57833e --- /dev/null +++ b/library/std/src/sys/exit.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/exit.rs \ No newline at end of file diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs deleted file mode 100644 index 02d61a6..0000000 --- a/library/std/src/sys/fd/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Platform-dependent file descriptor abstraction. - -#![forbid(unsafe_op_in_unsafe_fn)] - -cfg_select! { - any(target_family = "unix", target_os = "wasi") => { - mod unix; - pub use unix::*; - } - target_os = "hermit" => { - mod hermit; - pub use hermit::*; - } - target_os = "motor" => { - mod motor; - pub use motor::*; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::*; - } - _ => {} -} diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs new file mode 120000 index 0000000..694a403 --- /dev/null +++ b/library/std/src/sys/fd/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/fd/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs deleted file mode 100644 index 4d47d39..0000000 --- a/library/std/src/sys/fs/common.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![allow(dead_code)] // not used on all platforms - -use crate::io::{self, Error, ErrorKind}; -use crate::path::{Path, PathBuf}; -use crate::sys::fs::{File, OpenOptions}; -use crate::sys::helpers::ignore_notfound; -use crate::{fmt, fs}; - -pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( - ErrorKind::InvalidInput, - "the source path is neither a regular file nor a symlink to a regular file", -); - -pub fn copy(from: &Path, to: &Path) -> io::Result { - let mut reader = fs::File::open(from)?; - let metadata = reader.metadata()?; - - if !metadata.is_file() { - return Err(NOT_FILE_ERROR); - } - - let mut writer = fs::File::create(to)?; - let perm = metadata.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = fs::symlink_metadata(path)?.file_type(); - if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in fs::read_dir(path)? { - let result: io::Result<()> = try { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - fs::remove_file(&child.path())?; - } - }; - // ignore internal NotFound errors to prevent race conditions - if let Err(err) = &result - && err.kind() != io::ErrorKind::NotFound - { - return result; - } - } - ignore_notfound(fs::remove_dir(path)) -} - -pub fn exists(path: &Path) -> io::Result { - match fs::metadata(path) { - Ok(_) => Ok(true), - Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), - Err(error) => Err(error), - } -} - -pub struct Dir { - path: PathBuf, -} - -impl Dir { - pub fn open(path: &Path, _opts: &OpenOptions) -> io::Result { - path.canonicalize().map(|path| Self { path }) - } - - pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { - File::open(&self.path.join(path), &opts) - } -} - -impl fmt::Debug for Dir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Dir").field("path", &self.path).finish() - } -} diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs new file mode 120000 index 0000000..221beb3 --- /dev/null +++ b/library/std/src/sys/fs/common.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/fs/common.rs \ No newline at end of file diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs deleted file mode 100644 index 0c297c5..0000000 --- a/library/std/src/sys/fs/mod.rs +++ /dev/null @@ -1,173 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -use crate::io; -use crate::path::{Path, PathBuf}; - -pub mod common; - -cfg_select! { - any(target_family = "unix", target_os = "wasi") => { - mod unix; - use unix as imp; - #[cfg(not(target_os = "wasi"))] - pub use unix::{chown, fchown, lchown, mkfifo}; - #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))] - pub use unix::chroot; - #[cfg(not(target_os = "wasi"))] - pub(crate) use unix::debug_assert_fd_is_open; - #[cfg(any(target_os = "linux", target_os = "android"))] - pub(super) use unix::CachedFileMetadata; - use crate::sys::helpers::run_path_with_cstr as with_native_path; - } - target_os = "windows" => { - mod windows; - use windows as imp; - pub use windows::{symlink_inner, junction_point}; - use crate::sys::path::with_native_path; - } - target_os = "hermit" => { - mod hermit; - use hermit as imp; - } - target_os = "motor" => { - mod motor; - use motor as imp; - } - target_os = "solid_asp3" => { - mod solid; - use solid as imp; - } - target_os = "uefi" => { - mod uefi; - use uefi as imp; - } - target_os = "vexos" => { - mod vexos; - use vexos as imp; - } - _ => { - mod unsupported; - use unsupported as imp; - } -} - -// FIXME: Replace this with platform-specific path conversion functions. -#[cfg(not(any(target_family = "unix", target_os = "windows", target_os = "wasi")))] -#[inline] -pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { - f(path) -} - -pub use imp::{ - Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, - ReadDir, -}; - -pub fn read_dir(path: &Path) -> io::Result { - // FIXME: use with_native_path on all platforms - imp::readdir(path) -} - -pub fn remove_file(path: &Path) -> io::Result<()> { - with_native_path(path, &imp::unlink) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - with_native_path(old, &|old| with_native_path(new, &|new| imp::rename(old, new))) -} - -pub fn remove_dir(path: &Path) -> io::Result<()> { - with_native_path(path, &imp::rmdir) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - // FIXME: use with_native_path on all platforms - #[cfg(not(windows))] - return imp::remove_dir_all(path); - #[cfg(windows)] - with_native_path(path, &imp::remove_dir_all) -} - -pub fn read_link(path: &Path) -> io::Result { - with_native_path(path, &imp::readlink) -} - -pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { - // FIXME: use with_native_path on all platforms - #[cfg(windows)] - return imp::symlink(original, link); - #[cfg(not(windows))] - with_native_path(original, &|original| { - with_native_path(link, &|link| imp::symlink(original, link)) - }) -} - -pub fn hard_link(original: &Path, link: &Path) -> io::Result<()> { - with_native_path(original, &|original| { - with_native_path(link, &|link| imp::link(original, link)) - }) -} - -pub fn metadata(path: &Path) -> io::Result { - with_native_path(path, &imp::stat) -} - -pub fn symlink_metadata(path: &Path) -> io::Result { - with_native_path(path, &imp::lstat) -} - -pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { - with_native_path(path, &|path| imp::set_perm(path, perm.clone())) -} - -#[cfg(all(unix, not(target_os = "vxworks")))] -pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> { - use crate::fs::OpenOptions; - - let mut options = OpenOptions::new(); - - // ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it. - // Their filesystems do not have symbolic links, so no special handling is required. - #[cfg(not(any(target_os = "espidf", target_os = "horizon")))] - { - use crate::os::unix::fs::OpenOptionsExt; - options.custom_flags(libc::O_NOFOLLOW); - } - - options.open(path)?.set_permissions(perm) -} - -#[cfg(any(not(unix), target_os = "vxworks"))] -pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> { - crate::unimplemented!( - "`set_permissions_nofollow` is currently only implemented on Unix platforms" - ) -} - -pub fn canonicalize(path: &Path) -> io::Result { - with_native_path(path, &imp::canonicalize) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result { - // FIXME: use with_native_path on all platforms - #[cfg(not(windows))] - return imp::copy(from, to); - #[cfg(windows)] - with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to))) -} - -pub fn exists(path: &Path) -> io::Result { - // FIXME: use with_native_path on all platforms - #[cfg(not(windows))] - return imp::exists(path); - #[cfg(windows)] - with_native_path(path, &imp::exists) -} - -pub fn set_times(path: &Path, times: FileTimes) -> io::Result<()> { - with_native_path(path, &|path| imp::set_times(path, times.clone())) -} - -pub fn set_times_nofollow(path: &Path, times: FileTimes) -> io::Result<()> { - with_native_path(path, &|path| imp::set_times_nofollow(path, times.clone())) -} diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs new file mode 120000 index 0000000..dc8d563 --- /dev/null +++ b/library/std/src/sys/fs/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/fs/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs deleted file mode 100644 index 069b4fb..0000000 --- a/library/std/src/sys/fs/unsupported.rs +++ /dev/null @@ -1,362 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::fs::TryLockError; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; -use crate::path::{Path, PathBuf}; -pub use crate::sys::fs::common::Dir; -use crate::sys::time::SystemTime; -use crate::sys::unsupported; - -pub struct File(!); - -pub struct FileAttr(!); - -pub struct ReadDir(!); - -pub struct DirEntry(!); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -#[derive(Copy, Clone, Debug, Default)] -pub struct FileTimes {} - -pub struct FilePermissions(!); - -pub struct FileType(!); - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.0 - } - - pub fn perm(&self) -> FilePermissions { - self.0 - } - - pub fn file_type(&self) -> FileType { - self.0 - } - - pub fn modified(&self) -> io::Result { - self.0 - } - - pub fn accessed(&self) -> io::Result { - self.0 - } - - pub fn created(&self) -> io::Result { - self.0 - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - self.0 - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - self.0 - } - - pub fn set_readonly(&mut self, _readonly: bool) { - self.0 - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - self.0 - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - self.0 - } -} - -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -impl FileTimes { - pub fn set_accessed(&mut self, _t: SystemTime) {} - pub fn set_modified(&mut self, _t: SystemTime) {} -} - -impl FileType { - pub fn is_dir(&self) -> bool { - self.0 - } - - pub fn is_file(&self) -> bool { - self.0 - } - - pub fn is_symlink(&self) -> bool { - self.0 - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - self.0 - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - self.0 - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - self.0 - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - self.0 - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - self.0 - } - - pub fn file_name(&self) -> OsString { - self.0 - } - - pub fn metadata(&self) -> io::Result { - self.0 - } - - pub fn file_type(&self) -> io::Result { - self.0 - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - self.0 - } - - pub fn fsync(&self) -> io::Result<()> { - self.0 - } - - pub fn datasync(&self) -> io::Result<()> { - self.0 - } - - pub fn lock(&self) -> io::Result<()> { - self.0 - } - - pub fn lock_shared(&self) -> io::Result<()> { - self.0 - } - - pub fn try_lock(&self) -> Result<(), TryLockError> { - self.0 - } - - pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - self.0 - } - - pub fn unlock(&self) -> io::Result<()> { - self.0 - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - self.0 - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - self.0 - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 - } - - pub fn is_read_vectored(&self) -> bool { - self.0 - } - - pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.0 - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - self.0 - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - self.0 - } - - pub fn is_write_vectored(&self) -> bool { - self.0 - } - - pub fn flush(&self) -> io::Result<()> { - self.0 - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - self.0 - } - - pub fn size(&self) -> Option> { - self.0 - } - - pub fn tell(&self) -> io::Result { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - self.0 - } - - pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - self.0 - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { - unsupported() -} - -pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { - unsupported() -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn exists(_path: &Path) -> io::Result { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs new file mode 120000 index 0000000..286d0cf --- /dev/null +++ b/library/std/src/sys/fs/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/fs/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/helpers/mod.rs b/library/std/src/sys/helpers/mod.rs deleted file mode 100644 index a623679..0000000 --- a/library/std/src/sys/helpers/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Small helper functions used inside `sys`. -//! -//! If any of these have uses outside of `sys`, please move them to a different -//! module. - -#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. -mod small_c_string; -#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. -mod wstr; - -#[cfg(test)] -mod tests; - -#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. -pub use small_c_string::{run_path_with_cstr, run_with_cstr}; -#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. -pub use wstr::WStrUnits; - -/// Computes `(value*numerator)/denom` without overflow, as long as both -/// `numerator*denom` and the overall result fit into `u64` (which is the case -/// for our time conversions). -#[cfg_attr(not(target_os = "windows"), allow(unused))] // Not used on all platforms. -pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 { - let q = value / denom; - let r = value % denom; - // Decompose value as (value/denom*denom + value%denom), - // substitute into (value*numerator)/denom and simplify. - // r < denom, so (denom*numerator) is the upper bound of (r*numerator) - q * numerator + r * numerator / denom -} - -#[cfg_attr(not(target_os = "linux"), allow(unused))] // Not used on all platforms. -pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> { - match result { - Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()), - Ok(_) => Ok(()), - Err(err) => Err(err), - } -} diff --git a/library/std/src/sys/helpers/mod.rs b/library/std/src/sys/helpers/mod.rs new file mode 120000 index 0000000..c943a6b --- /dev/null +++ b/library/std/src/sys/helpers/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/helpers/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/helpers/small_c_string.rs b/library/std/src/sys/helpers/small_c_string.rs deleted file mode 100644 index f54505a..0000000 --- a/library/std/src/sys/helpers/small_c_string.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::ffi::{CStr, CString}; -use crate::mem::MaybeUninit; -use crate::path::Path; -use crate::{io, ptr, slice}; - -// Make sure to stay under 4096 so the compiler doesn't insert a probe frame: -// https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html -#[cfg(not(target_os = "espidf"))] -const MAX_STACK_ALLOCATION: usize = 384; -#[cfg(target_os = "espidf")] -const MAX_STACK_ALLOCATION: usize = 32; - -const NUL_ERR: io::Error = - io::const_error!(io::ErrorKind::InvalidInput, "file name contained an unexpected NUL byte"); - -#[inline] -pub fn run_path_with_cstr(path: &Path, f: &dyn Fn(&CStr) -> io::Result) -> io::Result { - run_with_cstr(path.as_os_str().as_encoded_bytes(), f) -} - -#[inline] -pub fn run_with_cstr(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result) -> io::Result { - // Dispatch and dyn erase the closure type to prevent mono bloat. - // See https://github.com/rust-lang/rust/pull/121101. - if bytes.len() >= MAX_STACK_ALLOCATION { - run_with_cstr_allocating(bytes, f) - } else { - unsafe { run_with_cstr_stack(bytes, f) } - } -} - -/// # Safety -/// -/// `bytes` must have a length less than `MAX_STACK_ALLOCATION`. -unsafe fn run_with_cstr_stack( - bytes: &[u8], - f: &dyn Fn(&CStr) -> io::Result, -) -> io::Result { - let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); - let buf_ptr = buf.as_mut_ptr() as *mut u8; - - unsafe { - ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len()); - buf_ptr.add(bytes.len()).write(0); - } - - match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) { - Ok(s) => f(s), - Err(_) => Err(NUL_ERR), - } -} - -#[cold] -#[inline(never)] -fn run_with_cstr_allocating(bytes: &[u8], f: &dyn Fn(&CStr) -> io::Result) -> io::Result { - match CString::new(bytes) { - Ok(s) => f(&s), - Err(_) => Err(NUL_ERR), - } -} diff --git a/library/std/src/sys/helpers/small_c_string.rs b/library/std/src/sys/helpers/small_c_string.rs new file mode 120000 index 0000000..4d23b5d --- /dev/null +++ b/library/std/src/sys/helpers/small_c_string.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/helpers/small_c_string.rs \ No newline at end of file diff --git a/library/std/src/sys/helpers/tests.rs b/library/std/src/sys/helpers/tests.rs deleted file mode 100644 index b67fdb9..0000000 --- a/library/std/src/sys/helpers/tests.rs +++ /dev/null @@ -1,73 +0,0 @@ -use core::iter::repeat; - -use super::mul_div_u64; -use super::small_c_string::run_path_with_cstr; -use crate::ffi::CString; -use crate::hint::black_box; -use crate::path::Path; - -#[test] -fn stack_allocation_works() { - let path = Path::new("abc"); - let result = run_path_with_cstr(path, &|p| { - assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap()); - Ok(42) - }); - assert_eq!(result.unwrap(), 42); -} - -#[test] -fn stack_allocation_fails() { - let path = Path::new("ab\0"); - assert!(run_path_with_cstr::<()>(path, &|_| unreachable!()).is_err()); -} - -#[test] -fn heap_allocation_works() { - let path = repeat("a").take(384).collect::(); - let path = Path::new(&path); - let result = run_path_with_cstr(path, &|p| { - assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap()); - Ok(42) - }); - assert_eq!(result.unwrap(), 42); -} - -#[test] -fn heap_allocation_fails() { - let mut path = repeat("a").take(384).collect::(); - path.push('\0'); - let path = Path::new(&path); - assert!(run_path_with_cstr::<()>(path, &|_| unreachable!()).is_err()); -} - -#[bench] -fn bench_stack_path_alloc(b: &mut test::Bencher) { - let path = repeat("a").take(383).collect::(); - let p = Path::new(&path); - b.iter(|| { - run_path_with_cstr(p, &|cstr| { - black_box(cstr); - Ok(()) - }) - .unwrap(); - }); -} - -#[bench] -fn bench_heap_path_alloc(b: &mut test::Bencher) { - let path = repeat("a").take(384).collect::(); - let p = Path::new(&path); - b.iter(|| { - run_path_with_cstr(p, &|cstr| { - black_box(cstr); - Ok(()) - }) - .unwrap(); - }); -} - -#[test] -fn test_muldiv() { - assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); -} diff --git a/library/std/src/sys/helpers/tests.rs b/library/std/src/sys/helpers/tests.rs new file mode 120000 index 0000000..13197a4 --- /dev/null +++ b/library/std/src/sys/helpers/tests.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/helpers/tests.rs \ No newline at end of file diff --git a/library/std/src/sys/helpers/wstr.rs b/library/std/src/sys/helpers/wstr.rs deleted file mode 100644 index 9c4b8e0..0000000 --- a/library/std/src/sys/helpers/wstr.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! This module contains constructs to work with 16-bit characters (UCS-2 or UTF-16) - -use crate::marker::PhantomData; -use crate::num::NonZero; -use crate::ptr::NonNull; - -/// A safe iterator over a LPWSTR -/// (aka a pointer to a series of UTF-16 code units terminated by a NULL). -pub struct WStrUnits<'a> { - // The pointer must never be null... - lpwstr: NonNull, - // ...and the memory it points to must be valid for this lifetime. - lifetime: PhantomData<&'a [u16]>, -} - -impl WStrUnits<'_> { - /// Creates the iterator. Returns `None` if `lpwstr` is null. - /// - /// SAFETY: `lpwstr` must point to a null-terminated wide string that lives - /// at least as long as the lifetime of this struct. - pub unsafe fn new(lpwstr: *const u16) -> Option { - Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData }) - } - - pub fn peek(&self) -> Option> { - // SAFETY: It's always safe to read the current item because we don't - // ever move out of the array's bounds. - unsafe { NonZero::new(*self.lpwstr.as_ptr()) } - } - - /// Advance the iterator while `predicate` returns true. - /// Returns the number of items it advanced by. - pub fn advance_while) -> bool>(&mut self, mut predicate: P) -> usize { - let mut counter = 0; - while let Some(w) = self.peek() { - if !predicate(w) { - break; - } - counter += 1; - self.next(); - } - counter - } -} - -impl Iterator for WStrUnits<'_> { - // This can never return zero as that marks the end of the string. - type Item = NonZero; - - fn next(&mut self) -> Option { - // SAFETY: If NULL is reached we immediately return. - // Therefore it's safe to advance the pointer after that. - unsafe { - let next = self.peek()?; - self.lpwstr = NonNull::new_unchecked(self.lpwstr.as_ptr().add(1)); - Some(next) - } - } -} diff --git a/library/std/src/sys/helpers/wstr.rs b/library/std/src/sys/helpers/wstr.rs new file mode 120000 index 0000000..23b1ee1 --- /dev/null +++ b/library/std/src/sys/helpers/wstr.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/helpers/wstr.rs \ No newline at end of file diff --git a/library/std/src/sys/io/error/generic.rs b/library/std/src/sys/io/error/generic.rs deleted file mode 100644 index fc70fba..0000000 --- a/library/std/src/sys/io/error/generic.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub fn errno() -> i32 { - 0 -} - -pub fn is_interrupted(_code: i32) -> bool { - false -} - -pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind { - crate::io::ErrorKind::Uncategorized -} - -pub fn error_string(_errno: i32) -> String { - "operation successful".to_string() -} diff --git a/library/std/src/sys/io/error/generic.rs b/library/std/src/sys/io/error/generic.rs new file mode 120000 index 0000000..5b942e8 --- /dev/null +++ b/library/std/src/sys/io/error/generic.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/io/error/generic.rs \ No newline at end of file diff --git a/library/std/src/sys/io/io_slice/unsupported.rs b/library/std/src/sys/io/io_slice/unsupported.rs deleted file mode 100644 index 1572cac..0000000 --- a/library/std/src/sys/io/io_slice/unsupported.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::mem; - -#[derive(Copy, Clone)] -pub struct IoSlice<'a>(&'a [u8]); - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - self.0 = &self.0[n..] - } - - #[inline] - pub const fn as_slice(&self) -> &'a [u8] { - self.0 - } -} - -pub struct IoSliceMut<'a>(&'a mut [u8]); - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - let slice = mem::take(&mut self.0); - let (_, remaining) = slice.split_at_mut(n); - self.0 = remaining; - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } - - #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { - self.0 - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - self.0 - } -} diff --git a/library/std/src/sys/io/io_slice/unsupported.rs b/library/std/src/sys/io/io_slice/unsupported.rs new file mode 120000 index 0000000..f0fb428 --- /dev/null +++ b/library/std/src/sys/io/io_slice/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/io/io_slice/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/io/is_terminal/unsupported.rs b/library/std/src/sys/io/is_terminal/unsupported.rs deleted file mode 100644 index cee4add..0000000 --- a/library/std/src/sys/io/is_terminal/unsupported.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn is_terminal(_: &T) -> bool { - false -} diff --git a/library/std/src/sys/io/is_terminal/unsupported.rs b/library/std/src/sys/io/is_terminal/unsupported.rs new file mode 120000 index 0000000..59fb3a9 --- /dev/null +++ b/library/std/src/sys/io/is_terminal/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/io/is_terminal/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/io/kernel_copy/mod.rs b/library/std/src/sys/io/kernel_copy/mod.rs deleted file mode 100644 index a892794..0000000 --- a/library/std/src/sys/io/kernel_copy/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub enum CopyState { - #[cfg_attr(not(any(target_os = "linux", target_os = "android")), expect(dead_code))] - Ended(u64), - Fallback(u64), -} - -cfg_select! { - any(target_os = "linux", target_os = "android") => { - mod linux; - pub use linux::kernel_copy; - } - _ => { - use crate::io::{Result, Read, Write}; - - pub fn kernel_copy(_reader: &mut R, _writer: &mut W) -> Result - where - R: Read, - W: Write, - { - Ok(CopyState::Fallback(0)) - } - } -} diff --git a/library/std/src/sys/io/kernel_copy/mod.rs b/library/std/src/sys/io/kernel_copy/mod.rs new file mode 120000 index 0000000..c3ba74b --- /dev/null +++ b/library/std/src/sys/io/kernel_copy/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/io/kernel_copy/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs deleted file mode 100644 index b3587ab..0000000 --- a/library/std/src/sys/io/mod.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -mod error; - -mod io_slice { - cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { - mod iovec; - pub use iovec::*; - } - target_os = "windows" => { - mod windows; - pub use windows::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } - } -} - -mod is_terminal { - cfg_select! { - any(target_family = "unix", target_os = "wasi") => { - mod isatty; - pub use isatty::*; - } - target_os = "windows" => { - mod windows; - pub use windows::*; - } - target_os = "hermit" => { - mod hermit; - pub use hermit::*; - } - target_os = "motor" => { - mod motor; - pub use motor::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } - } -} - -mod kernel_copy; - -#[cfg_attr(not(target_os = "linux"), allow(unused_imports))] -#[cfg(all( - target_family = "unix", - not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")) -))] -pub use error::errno_location; -#[cfg_attr(not(target_os = "linux"), allow(unused_imports))] -#[cfg(any( - all(target_family = "unix", not(any(target_os = "vxworks", target_os = "rtems"))), - target_os = "wasi", -))] -pub use error::set_errno; -pub use error::{RawOsError, decode_error_kind, errno, error_string, is_interrupted}; -pub use io_slice::{IoSlice, IoSliceMut}; -pub use is_terminal::is_terminal; -pub use kernel_copy::{CopyState, kernel_copy}; - -// Bare metal platforms usually have very small amounts of RAM -// (in the order of hundreds of KB) -pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs new file mode 120000 index 0000000..a2e46a1 --- /dev/null +++ b/library/std/src/sys/io/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/io/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs deleted file mode 100644 index 5ad2397..0000000 --- a/library/std/src/sys/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![allow(unsafe_op_in_unsafe_fn)] - -mod alloc; -mod configure_builtins; -mod helpers; -mod pal; -mod personality; - -pub mod args; -pub mod backtrace; -pub mod cmath; -pub mod env; -pub mod env_consts; -pub mod exit; -pub mod fd; -pub mod fs; -pub mod io; -pub mod net; -pub mod os_str; -pub mod path; -pub mod pipe; -pub mod platform_version; -pub mod process; -pub mod random; -pub mod stdio; -pub mod sync; -pub mod thread; -pub mod thread_local; -pub mod time; - -// FIXME(117276): remove this, move feature implementations into individual -// submodules. -pub use pal::*; - -/// A trait for viewing representations from std types. -#[cfg_attr(not(target_os = "linux"), allow(unused))] -pub(crate) trait AsInner { - fn as_inner(&self) -> &Inner; -} - -/// A trait for viewing representations from std types. -#[cfg_attr(not(target_os = "linux"), allow(unused))] -pub(crate) trait AsInnerMut { - fn as_inner_mut(&mut self) -> &mut Inner; -} - -/// A trait for extracting representations from std types. -pub(crate) trait IntoInner { - fn into_inner(self) -> Inner; -} - -/// A trait for creating std types from internal representations. -pub(crate) trait FromInner { - fn from_inner(inner: Inner) -> Self; -} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs new file mode 120000 index 0000000..62d64a5 --- /dev/null +++ b/library/std/src/sys/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs deleted file mode 100644 index 2f06491..0000000 --- a/library/std/src/sys/net/connection/mod.rs +++ /dev/null @@ -1,61 +0,0 @@ -cfg_select! { - any( - all(target_family = "unix", not(target_os = "l4re")), - target_os = "windows", - target_os = "hermit", - all(target_os = "wasi", any(target_env = "p2", target_env = "p3")), - target_os = "solid_asp3", - ) => { - mod socket; - pub use socket::*; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::*; - } - all(target_os = "wasi", target_env = "p1") => { - mod wasip1; - pub use wasip1::*; - } - target_os = "motor" => { - mod motor; - pub use motor::*; - } - target_os = "xous" => { - mod xous; - pub use xous::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } -} - -#[cfg_attr( - // Make sure that this is used on some platforms at least. - not(any(target_os = "linux", target_os = "windows")), - allow(dead_code) -)] -fn each_addr(addr: A, mut f: F) -> crate::io::Result -where - F: FnMut(&crate::net::SocketAddr) -> crate::io::Result, -{ - use crate::io::Error; - - let mut last_err = None; - for addr in addr.to_socket_addrs()? { - match f(&addr) { - Ok(l) => return Ok(l), - Err(e) => last_err = Some(e), - } - } - - match last_err { - Some(err) => Err(err), - None => Err(Error::NO_ADDRESSES), - } -} diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs new file mode 120000 index 0000000..d824a29 --- /dev/null +++ b/library/std/src/sys/net/connection/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/net/connection/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs deleted file mode 100644 index fb18e8d..0000000 --- a/library/std/src/sys/net/connection/unsupported.rs +++ /dev/null @@ -1,316 +0,0 @@ -use crate::fmt; -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; -use crate::sys::unsupported; -use crate::time::Duration; - -pub struct TcpStream(!); - -impl TcpStream { - pub fn connect(_: A) -> io::Result { - unsupported() - } - - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unsupported() - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn read_timeout(&self) -> io::Result> { - self.0 - } - - pub fn write_timeout(&self) -> io::Result> { - self.0 - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn read(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { - self.0 - } - - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 - } - - pub fn is_read_vectored(&self) -> bool { - self.0 - } - - pub fn write(&self, _: &[u8]) -> io::Result { - self.0 - } - - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - self.0 - } - - pub fn is_write_vectored(&self) -> bool { - self.0 - } - - pub fn peer_addr(&self) -> io::Result { - self.0 - } - - pub fn socket_addr(&self) -> io::Result { - self.0 - } - - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_linger(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn linger(&self) -> io::Result> { - self.0 - } - - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn nodelay(&self) -> io::Result { - self.0 - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn ttl(&self) -> io::Result { - self.0 - } - - pub fn take_error(&self) -> io::Result> { - self.0 - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 - } -} - -impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub struct TcpListener(!); - -impl TcpListener { - pub fn bind(_: A) -> io::Result { - unsupported() - } - - pub fn socket_addr(&self) -> io::Result { - self.0 - } - - pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn ttl(&self) -> io::Result { - self.0 - } - - pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn only_v6(&self) -> io::Result { - self.0 - } - - pub fn take_error(&self) -> io::Result> { - self.0 - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 - } -} - -impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub struct UdpSocket(!); - -impl UdpSocket { - pub fn bind(_: A) -> io::Result { - unsupported() - } - - pub fn peer_addr(&self) -> io::Result { - self.0 - } - - pub fn socket_addr(&self) -> io::Result { - self.0 - } - - pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.0 - } - - pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.0 - } - - pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result { - self.0 - } - - pub fn duplicate(&self) -> io::Result { - self.0 - } - - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - self.0 - } - - pub fn read_timeout(&self) -> io::Result> { - self.0 - } - - pub fn write_timeout(&self) -> io::Result> { - self.0 - } - - pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn broadcast(&self) -> io::Result { - self.0 - } - - pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn multicast_loop_v4(&self) -> io::Result { - self.0 - } - - pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - self.0 - } - - pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn multicast_loop_v6(&self) -> io::Result { - self.0 - } - - pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - self.0 - } - - pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - self.0 - } - - pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - self.0 - } - - pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - self.0 - } - - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - self.0 - } - - pub fn ttl(&self) -> io::Result { - self.0 - } - - pub fn take_error(&self) -> io::Result> { - self.0 - } - - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - self.0 - } - - pub fn recv(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn peek(&self, _: &mut [u8]) -> io::Result { - self.0 - } - - pub fn send(&self, _: &[u8]) -> io::Result { - self.0 - } - - pub fn connect(&self, _: A) -> io::Result<()> { - self.0 - } -} - -impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -pub struct LookupHost(!); - -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { - self.0 - } -} - -pub fn lookup_host(_host: &str, _port: u16) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs new file mode 120000 index 0000000..36a6b07 --- /dev/null +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/net/connection/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs deleted file mode 100644 index 65fcd6b..0000000 --- a/library/std/src/sys/net/hostname/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -cfg_select! { - all(target_family = "unix", not(target_os = "espidf")) => { - mod unix; - pub use unix::hostname; - } - // `GetHostNameW` is only available starting with Windows 8. - all(target_os = "windows", not(target_vendor = "win7")) => { - mod windows; - pub use windows::hostname; - } - _ => { - mod unsupported; - pub use unsupported::hostname; - } -} diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs new file mode 120000 index 0000000..7a6ab54 --- /dev/null +++ b/library/std/src/sys/net/hostname/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/net/hostname/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/net/hostname/unsupported.rs b/library/std/src/sys/net/hostname/unsupported.rs deleted file mode 100644 index d868f68..0000000 --- a/library/std/src/sys/net/hostname/unsupported.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::ffi::OsString; -use crate::io::{Error, Result}; - -pub fn hostname() -> Result { - Err(Error::UNSUPPORTED_PLATFORM) -} diff --git a/library/std/src/sys/net/hostname/unsupported.rs b/library/std/src/sys/net/hostname/unsupported.rs new file mode 120000 index 0000000..5521501 --- /dev/null +++ b/library/std/src/sys/net/hostname/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/net/hostname/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs deleted file mode 100644 index bfe5cf5..0000000 --- a/library/std/src/sys/net/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// This module contains the implementations of `TcpStream`, `TcpListener` and -/// `UdpSocket` as well as related functionality like DNS resolving. -mod connection; -pub use connection::*; - -mod hostname; -pub use hostname::hostname; diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs new file mode 120000 index 0000000..e19fa6a --- /dev/null +++ b/library/std/src/sys/net/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/net/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs deleted file mode 100644 index 5482663..0000000 --- a/library/std/src/sys/os_str/bytes.rs +++ /dev/null @@ -1,363 +0,0 @@ -//! The underlying OsString/OsStr implementation on Unix and many other -//! systems: just a `Vec`/`[u8]`. - -use core::clone::CloneToUninit; - -use crate::borrow::Cow; -use crate::bstr::ByteStr; -use crate::collections::TryReserveError; -use crate::rc::Rc; -use crate::sync::Arc; -use crate::sys::{AsInner, FromInner, IntoInner}; -use crate::{fmt, mem, str}; - -#[cfg(test)] -mod tests; - -#[derive(Hash)] -#[repr(transparent)] -pub struct Buf { - pub inner: Vec, -} - -#[repr(transparent)] -pub struct Slice { - pub inner: [u8], -} - -impl IntoInner> for Buf { - fn into_inner(self) -> Vec { - self.inner - } -} - -impl FromInner> for Buf { - fn from_inner(inner: Vec) -> Self { - Buf { inner } - } -} - -impl AsInner<[u8]> for Buf { - #[inline] - fn as_inner(&self) -> &[u8] { - &self.inner - } -} - -impl fmt::Debug for Buf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), f) - } -} - -impl fmt::Display for Buf { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), f) - } -} - -impl fmt::Debug for Slice { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.inner.utf8_chunks().debug(), f) - } -} - -impl fmt::Display for Slice { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(ByteStr::new(&self.inner), f) - } -} - -impl Clone for Buf { - #[inline] - fn clone(&self) -> Self { - Buf { inner: self.inner.clone() } - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - self.inner.clone_from(&source.inner) - } -} - -impl Buf { - #[inline] - pub fn into_encoded_bytes(self) -> Vec { - self.inner - } - - #[inline] - pub unsafe fn from_encoded_bytes_unchecked(s: Vec) -> Self { - Self { inner: s } - } - - #[inline] - pub fn into_string(self) -> Result { - String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() }) - } - - #[inline] - pub const fn from_string(s: String) -> Buf { - Buf { inner: s.into_bytes() } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Buf { - Buf { inner: Vec::with_capacity(capacity) } - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear() - } - - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - - #[inline] - pub fn push_slice(&mut self, s: &Slice) { - self.inner.extend_from_slice(&s.inner) - } - - #[inline] - pub fn push_str(&mut self, s: &str) { - self.inner.extend_from_slice(s.as_bytes()); - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.inner.reserve(additional) - } - - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.inner.try_reserve(additional) - } - - #[inline] - pub fn reserve_exact(&mut self, additional: usize) { - self.inner.reserve_exact(additional) - } - - #[inline] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.inner.try_reserve_exact(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit() - } - - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.inner.shrink_to(min_capacity) - } - - #[inline] - pub fn as_slice(&self) -> &Slice { - // SAFETY: Slice is just a wrapper for [u8], - // and self.inner.as_slice() returns &[u8]. - // Therefore, transmuting &[u8] to &Slice is safe. - unsafe { mem::transmute(self.inner.as_slice()) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut Slice { - // SAFETY: Slice is just a wrapper for [u8], - // and self.inner.as_mut_slice() returns &mut [u8]. - // Therefore, transmuting &mut [u8] to &mut Slice is safe. - unsafe { mem::transmute(self.inner.as_mut_slice()) } - } - - #[inline] - pub fn leak<'a>(self) -> &'a mut Slice { - unsafe { mem::transmute(self.inner.leak()) } - } - - #[inline] - pub fn into_box(self) -> Box { - unsafe { mem::transmute(self.inner.into_boxed_slice()) } - } - - #[inline] - pub fn from_box(boxed: Box) -> Buf { - let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; - Buf { inner: inner.into_vec() } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - self.as_slice().into_arc() - } - - #[inline] - pub fn into_rc(&self) -> Rc { - self.as_slice().into_rc() - } - - /// Provides plumbing to `Vec::truncate` without giving full mutable access - /// to the `Vec`. - /// - /// # Safety - /// - /// The length must be at an `OsStr` boundary, according to - /// `Slice::check_public_boundary`. - #[inline] - pub unsafe fn truncate_unchecked(&mut self, len: usize) { - self.inner.truncate(len); - } - - /// Provides plumbing to `Vec::extend_from_slice` without giving full - /// mutable access to the `Vec`. - /// - /// # Safety - /// - /// The slice must be valid for the platform encoding (as described in - /// `OsStr::from_encoded_bytes_unchecked`). This encoding has no safety - /// requirements. - #[inline] - pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { - self.inner.extend_from_slice(other); - } -} - -impl Slice { - #[inline] - pub fn as_encoded_bytes(&self) -> &[u8] { - &self.inner - } - - #[inline] - pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice { - unsafe { mem::transmute(s) } - } - - #[track_caller] - #[inline] - pub fn check_public_boundary(&self, index: usize) { - if index == 0 || index == self.inner.len() { - return; - } - if index < self.inner.len() - && (self.inner[index - 1].is_ascii() || self.inner[index].is_ascii()) - { - return; - } - - slow_path(&self.inner, index); - - /// We're betting that typical splits will involve an ASCII character. - /// - /// Putting the expensive checks in a separate function generates notably - /// better assembly. - #[track_caller] - #[inline(never)] - fn slow_path(bytes: &[u8], index: usize) { - let (before, after) = bytes.split_at(index); - - // UTF-8 takes at most 4 bytes per codepoint, so we don't - // need to check more than that. - let after = after.get(..4).unwrap_or(after); - match str::from_utf8(after) { - Ok(_) => return, - Err(err) if err.valid_up_to() != 0 => return, - Err(_) => (), - } - - for len in 2..=4.min(index) { - let before = &before[index - len..]; - if str::from_utf8(before).is_ok() { - return; - } - } - - panic!("byte index {index} is not an OsStr boundary"); - } - } - - #[inline] - pub fn from_str(s: &str) -> &Slice { - unsafe { Slice::from_encoded_bytes_unchecked(s.as_bytes()) } - } - - #[inline] - pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { - str::from_utf8(&self.inner) - } - - #[inline] - pub fn to_string_lossy(&self) -> Cow<'_, str> { - String::from_utf8_lossy(&self.inner) - } - - #[inline] - pub fn to_owned(&self) -> Buf { - Buf { inner: self.inner.to_vec() } - } - - #[inline] - pub fn clone_into(&self, buf: &mut Buf) { - self.inner.clone_into(&mut buf.inner) - } - - #[inline] - pub fn empty_box() -> Box { - let boxed: Box<[u8]> = Default::default(); - unsafe { mem::transmute(boxed) } - } - - #[inline] - pub fn into_arc(&self) -> Arc { - let arc: Arc<[u8]> = Arc::from(&self.inner); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } - } - - #[inline] - pub fn into_rc(&self) -> Rc { - let rc: Rc<[u8]> = Rc::from(&self.inner); - unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } - } - - #[inline] - pub fn make_ascii_lowercase(&mut self) { - self.inner.make_ascii_lowercase() - } - - #[inline] - pub fn make_ascii_uppercase(&mut self) { - self.inner.make_ascii_uppercase() - } - - #[inline] - pub fn to_ascii_lowercase(&self) -> Buf { - Buf { inner: self.inner.to_ascii_lowercase() } - } - - #[inline] - pub fn to_ascii_uppercase(&self) -> Buf { - Buf { inner: self.inner.to_ascii_uppercase() } - } - - #[inline] - pub fn is_ascii(&self) -> bool { - self.inner.is_ascii() - } - - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { - self.inner.eq_ignore_ascii_case(&other.inner) - } -} - -#[unstable(feature = "clone_to_uninit", issue = "126799")] -unsafe impl CloneToUninit for Slice { - #[inline] - #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { - // SAFETY: we're just a transparent wrapper around [u8] - unsafe { self.inner.clone_to_uninit(dst) } - } -} diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs new file mode 120000 index 0000000..a50532b --- /dev/null +++ b/library/std/src/sys/os_str/bytes.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/os_str/bytes.rs \ No newline at end of file diff --git a/library/std/src/sys/os_str/bytes/tests.rs b/library/std/src/sys/os_str/bytes/tests.rs deleted file mode 100644 index e2a9904..0000000 --- a/library/std/src/sys/os_str/bytes/tests.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::*; - -#[test] -fn slice_debug_output() { - let input = unsafe { Slice::from_encoded_bytes_unchecked(b"\xF0hello,\tworld") }; - let expected = r#""\xF0hello,\tworld""#; - let output = format!("{input:?}"); - - assert_eq!(output, expected); -} - -#[test] -fn display() { - assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe { - Slice::from_encoded_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() - },); -} diff --git a/library/std/src/sys/os_str/bytes/tests.rs b/library/std/src/sys/os_str/bytes/tests.rs new file mode 120000 index 0000000..a1f8ad2 --- /dev/null +++ b/library/std/src/sys/os_str/bytes/tests.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/os_str/bytes/tests.rs \ No newline at end of file diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs deleted file mode 100644 index f7007cb..0000000 --- a/library/std/src/sys/os_str/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -cfg_select! { - any(target_os = "windows", target_os = "uefi") => { - mod wtf8; - pub use wtf8::{Buf, Slice}; - } - any(target_os = "motor") => { - mod utf8; - pub use utf8::{Buf, Slice}; - } - _ => { - mod bytes; - pub use bytes::{Buf, Slice}; - } -} diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs new file mode 120000 index 0000000..f5b88e8 --- /dev/null +++ b/library/std/src/sys/os_str/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/os_str/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs deleted file mode 100644 index d94b901..0000000 --- a/library/std/src/sys/pal/unsupported/common.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::io as std_io; - -// SAFETY: must be called only once during runtime initialization. -// NOTE: this is not guaranteed to run, for example when Rust code is called externally. -pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} - -// SAFETY: must be called only once during runtime cleanup. -// NOTE: this is not guaranteed to run, for example when the program aborts. -pub unsafe fn cleanup() {} - -pub fn unsupported() -> std_io::Result { - Err(unsupported_err()) -} - -pub fn unsupported_err() -> std_io::Error { - std_io::Error::UNSUPPORTED_PLATFORM -} - -pub fn abort_internal() -> ! { - core::intrinsics::abort(); -} diff --git a/library/std/src/sys/pal/unsupported/common.rs b/library/std/src/sys/pal/unsupported/common.rs new file mode 120000 index 0000000..e212bd7 --- /dev/null +++ b/library/std/src/sys/pal/unsupported/common.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unsupported/common.rs \ No newline at end of file diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs deleted file mode 100644 index 0f15781..0000000 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] - -pub mod os; - -mod common; -pub use common::*; diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs new file mode 120000 index 0000000..0fc4f50 --- /dev/null +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unsupported/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs deleted file mode 100644 index fe8adde..0000000 --- a/library/std/src/sys/pal/unsupported/os.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::unsupported; -use crate::ffi::{OsStr, OsString}; -use crate::marker::PhantomData; -use crate::path::{self, PathBuf}; -use crate::{fmt, io}; - -pub fn getcwd() -> io::Result { - unsupported() -} - -pub fn chdir(_: &path::Path) -> io::Result<()> { - unsupported() -} - -pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); - -pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { - panic!("unsupported") -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option { - self.0 - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths(_paths: I) -> Result -where - I: Iterator, - T: AsRef, -{ - Err(JoinPathsError) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "not supported on this platform yet".fmt(f) - } -} - -impl crate::error::Error for JoinPathsError {} - -pub fn current_exe() -> io::Result { - unsupported() -} - -pub fn temp_dir() -> PathBuf { - panic!("no filesystem on this platform") -} - -pub fn home_dir() -> Option { - None -} diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs new file mode 120000 index 0000000..c4bf68d --- /dev/null +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pal/unsupported/os.rs \ No newline at end of file diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs deleted file mode 100644 index bbb7577..0000000 --- a/library/std/src/sys/path/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -// 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; - mod windows_prefix; - pub use windows::*; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::*; - } - target_os = "solid_asp3" => { - mod unsupported_backslash; - pub use unsupported_backslash::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - target_os = "cygwin" => { - mod cygwin; - mod windows_prefix; - pub use cygwin::*; - } - _ => { - mod unix; - pub use unix::*; - } -} diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs new file mode 120000 index 0000000..af2c74c --- /dev/null +++ b/library/std/src/sys/path/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/path/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs deleted file mode 100644 index b49c39a..0000000 --- a/library/std/src/sys/path/unix.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::{Path, PathBuf, Prefix}; -use crate::{env, io}; - -path_separator_bytes!(b'/'); - -#[inline] -pub const fn is_verbatim_sep(b: u8) -> bool { - is_sep_byte(b) -} - -#[inline] -pub fn parse_prefix(_: &OsStr) -> Option> { - None -} - -pub const HAS_PREFIXES: bool = false; - -/// Make a POSIX path absolute without changing its semantics. -pub(crate) fn absolute(path: &Path) -> io::Result { - // This is mostly a wrapper around collecting `Path::components`, with - // exceptions made where this conflicts with the POSIX specification. - // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017 - // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 - - // Get the components, skipping the redundant leading "." component if it exists. - let mut components = path.strip_prefix(".").unwrap_or(path).components(); - let path_os = path.as_os_str().as_encoded_bytes(); - - let mut normalized = if path.is_absolute() { - // "If a pathname begins with two successive characters, the - // first component following the leading characters may be - // interpreted in an implementation-defined manner, although more than - // two leading characters shall be treated as a single - // character." - if path_os.starts_with(b"//") && !path_os.starts_with(b"///") { - components.next(); - PathBuf::from("//") - } else { - PathBuf::new() - } - } else { - env::current_dir()? - }; - normalized.extend(components); - - // "Interfaces using pathname resolution may specify additional constraints - // when a pathname that does not name an existing directory contains at - // least one non- character and contains one or more trailing - // characters". - // A trailing is also meaningful if "a symbolic link is - // encountered during pathname resolution". - if path_os.ends_with(b"/") { - normalized.push(""); - } - - Ok(normalized) -} - -pub(crate) fn is_absolute(path: &Path) -> bool { - if cfg!(any(unix, target_os = "hermit", target_os = "wasi", target_os = "motor")) { - path.has_root() - } else { - path.has_root() && path.prefix().is_some() - } -} diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs new file mode 120000 index 0000000..9351336 --- /dev/null +++ b/library/std/src/sys/path/unix.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/path/unix.rs \ No newline at end of file diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs deleted file mode 100644 index ef5112a..0000000 --- a/library/std/src/sys/personality/dwarf/eh.rs +++ /dev/null @@ -1,271 +0,0 @@ -//! Parsing of GCC-style Language-Specific Data Area (LSDA) -//! For details see: -//! * -//! * -//! * -//! * -//! * -//! -//! A reference implementation may be found in the GCC source tree -//! (`/libgcc/unwind-c.c` as of this writing). - -#![allow(non_upper_case_globals)] -#![allow(unused)] - -use core::ptr; - -use super::DwarfReader; - -pub const DW_EH_PE_omit: u8 = 0xFF; -pub const DW_EH_PE_absptr: u8 = 0x00; - -pub const DW_EH_PE_uleb128: u8 = 0x01; -pub const DW_EH_PE_udata2: u8 = 0x02; -pub const DW_EH_PE_udata4: u8 = 0x03; -pub const DW_EH_PE_udata8: u8 = 0x04; -pub const DW_EH_PE_sleb128: u8 = 0x09; -pub const DW_EH_PE_sdata2: u8 = 0x0A; -pub const DW_EH_PE_sdata4: u8 = 0x0B; -pub const DW_EH_PE_sdata8: u8 = 0x0C; - -pub const DW_EH_PE_pcrel: u8 = 0x10; -pub const DW_EH_PE_textrel: u8 = 0x20; -pub const DW_EH_PE_datarel: u8 = 0x30; -pub const DW_EH_PE_funcrel: u8 = 0x40; -pub const DW_EH_PE_aligned: u8 = 0x50; - -pub const DW_EH_PE_indirect: u8 = 0x80; - -#[derive(Copy, Clone)] -pub struct EHContext<'a> { - pub ip: *const u8, // Current instruction pointer - pub func_start: *const u8, // Pointer to the current function - pub get_text_start: &'a dyn Fn() -> *const u8, // Get pointer to the code section - pub get_data_start: &'a dyn Fn() -> *const u8, // Get pointer to the data section -} - -/// Landing pad. -type LPad = *const u8; -pub enum EHAction { - None, - Cleanup(LPad), - Catch(LPad), - Filter(LPad), - Terminate, -} - -/// 32-bit ARM Darwin platforms uses SjLj exceptions. -/// -/// The exception is watchOS armv7k (specifically that subarchitecture), which -/// instead uses DWARF Call Frame Information (CFI) unwinding. -/// -/// -pub const USING_SJLJ_EXCEPTIONS: bool = - cfg!(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm")); - -pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result { - if lsda.is_null() { - return Ok(EHAction::None); - } - - let func_start = context.func_start; - let mut reader = DwarfReader::new(lsda); - let lpad_base = unsafe { - let start_encoding = reader.read::(); - // base address for landing pad offsets - if start_encoding != DW_EH_PE_omit { - read_encoded_pointer(&mut reader, context, start_encoding)? - } else { - func_start - } - }; - let call_site_encoding = unsafe { - let ttype_encoding = reader.read::(); - if ttype_encoding != DW_EH_PE_omit { - // Rust doesn't analyze exception types, so we don't care about the type table - reader.read_uleb128(); - } - - reader.read::() - }; - let action_table = unsafe { - let call_site_table_length = reader.read_uleb128(); - reader.ptr.add(call_site_table_length as usize) - }; - let ip = context.ip; - - if !USING_SJLJ_EXCEPTIONS { - // read the callsite table - while reader.ptr < action_table { - unsafe { - // these are offsets rather than pointers; - let cs_start = read_encoded_offset(&mut reader, call_site_encoding)?; - let cs_len = read_encoded_offset(&mut reader, call_site_encoding)?; - let cs_lpad = read_encoded_offset(&mut reader, call_site_encoding)?; - let cs_action_entry = reader.read_uleb128(); - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - if ip < func_start.wrapping_add(cs_start) { - break; - } - if ip < func_start.wrapping_add(cs_start + cs_len) { - if cs_lpad == 0 { - return Ok(EHAction::None); - } else { - let lpad = lpad_base.wrapping_add(cs_lpad); - return Ok(interpret_cs_action(action_table, cs_action_entry, lpad)); - } - } - } - } - // Ip is not present in the table. This indicates a nounwind call. - Ok(EHAction::Terminate) - } else { - // SjLj version: - // The "IP" is an index into the call-site table, with two exceptions: - // -1 means 'no-action', and 0 means 'terminate'. - match ip.addr() as isize { - -1 => return Ok(EHAction::None), - 0 => return Ok(EHAction::Terminate), - _ => (), - } - let mut idx = ip.addr(); - loop { - let cs_lpad = unsafe { reader.read_uleb128() }; - let cs_action_entry = unsafe { reader.read_uleb128() }; - idx -= 1; - if idx == 0 { - // Can never have null landing pad for sjlj -- that would have - // been indicated by a -1 call site index. - // FIXME(strict provenance) - let lpad = ptr::with_exposed_provenance((cs_lpad + 1) as usize); - return Ok(unsafe { interpret_cs_action(action_table, cs_action_entry, lpad) }); - } - } - } -} - -unsafe fn interpret_cs_action( - action_table: *const u8, - cs_action_entry: u64, - lpad: LPad, -) -> EHAction { - if cs_action_entry == 0 { - // If cs_action_entry is 0 then this is a cleanup (Drop::drop). We run these - // for both Rust panics and foreign exceptions. - EHAction::Cleanup(lpad) - } else { - // If lpad != 0 and cs_action_entry != 0, we have to check ttype_index. - // If ttype_index == 0 under the condition, we take cleanup action. - let action_record = unsafe { action_table.offset(cs_action_entry as isize - 1) }; - let mut action_reader = DwarfReader::new(action_record); - let ttype_index = unsafe { action_reader.read_sleb128() }; - if ttype_index == 0 { - EHAction::Cleanup(lpad) - } else if ttype_index > 0 { - // Stop unwinding Rust panics at catch_unwind. - EHAction::Catch(lpad) - } else { - EHAction::Filter(lpad) - } - } -} - -#[inline] -fn round_up(unrounded: usize, align: usize) -> Result { - if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) } -} - -/// Reads an offset (`usize`) from `reader` whose encoding is described by `encoding`. -/// -/// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext]. -/// In addition the upper ("application") part must be zero. -/// -/// # Errors -/// Returns `Err` if `encoding` -/// * is not a valid DWARF Exception Header Encoding, -/// * is `DW_EH_PE_omit`, or -/// * has a non-zero application part. -/// -/// [LSB-dwarf-ext]: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html -unsafe fn read_encoded_offset(reader: &mut DwarfReader, encoding: u8) -> Result { - if encoding == DW_EH_PE_omit || encoding & 0xF0 != 0 { - return Err(()); - } - let result = unsafe { - match encoding & 0x0F { - // despite the name, LLVM also uses absptr for offsets instead of pointers - DW_EH_PE_absptr => reader.read::(), - DW_EH_PE_uleb128 => reader.read_uleb128() as usize, - DW_EH_PE_udata2 => reader.read::() as usize, - DW_EH_PE_udata4 => reader.read::() as usize, - DW_EH_PE_udata8 => reader.read::() as usize, - DW_EH_PE_sleb128 => reader.read_sleb128() as usize, - DW_EH_PE_sdata2 => reader.read::() as usize, - DW_EH_PE_sdata4 => reader.read::() as usize, - DW_EH_PE_sdata8 => reader.read::() as usize, - _ => return Err(()), - } - }; - Ok(result) -} - -/// Reads a pointer from `reader` whose encoding is described by `encoding`. -/// -/// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext]. -/// -/// # Errors -/// Returns `Err` if `encoding` -/// * is not a valid DWARF Exception Header Encoding, -/// * is `DW_EH_PE_omit`, or -/// * combines `DW_EH_PE_absptr` or `DW_EH_PE_aligned` application part with an integer encoding -/// (not `DW_EH_PE_absptr`) in the value format part. -/// -/// [LSB-dwarf-ext]: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html -unsafe fn read_encoded_pointer( - reader: &mut DwarfReader, - context: &EHContext<'_>, - encoding: u8, -) -> Result<*const u8, ()> { - if encoding == DW_EH_PE_omit { - return Err(()); - } - - let base_ptr = match encoding & 0x70 { - DW_EH_PE_absptr => core::ptr::null(), - // relative to address of the encoded value, despite the name - DW_EH_PE_pcrel => reader.ptr, - DW_EH_PE_funcrel => { - if context.func_start.is_null() { - return Err(()); - } - context.func_start - } - DW_EH_PE_textrel => (*context.get_text_start)(), - DW_EH_PE_datarel => (*context.get_data_start)(), - // aligned means the value is aligned to the size of a pointer - DW_EH_PE_aligned => { - reader.ptr = reader.ptr.with_addr(round_up(reader.ptr.addr(), size_of::<*const u8>())?); - core::ptr::null() - } - _ => return Err(()), - }; - - let mut ptr = if base_ptr.is_null() { - // any value encoding other than absptr would be nonsensical here; - // there would be no source of pointer provenance - if encoding & 0x0F != DW_EH_PE_absptr { - return Err(()); - } - unsafe { reader.read::<*const u8>() } - } else { - let offset = unsafe { read_encoded_offset(reader, encoding & 0x0F)? }; - base_ptr.wrapping_add(offset) - }; - - if encoding & DW_EH_PE_indirect != 0 { - ptr = unsafe { *(ptr.cast::<*const u8>()) }; - } - - Ok(ptr) -} diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs new file mode 120000 index 0000000..4af175e --- /dev/null +++ b/library/std/src/sys/personality/dwarf/eh.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/personality/dwarf/eh.rs \ No newline at end of file diff --git a/library/std/src/sys/personality/dwarf/mod.rs b/library/std/src/sys/personality/dwarf/mod.rs deleted file mode 100644 index 2bc9195..0000000 --- a/library/std/src/sys/personality/dwarf/mod.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Utilities for parsing DWARF-encoded data streams. -//! See , -//! DWARF-4 standard, Section 7 - "Data Representation" - -// This module is used only by x86_64-pc-windows-gnu for now, but we -// are compiling it everywhere to avoid regressions. -#![allow(unused)] -#![forbid(unsafe_op_in_unsafe_fn)] - -#[cfg(test)] -mod tests; - -pub mod eh; - -pub struct DwarfReader { - pub ptr: *const u8, -} - -impl DwarfReader { - pub fn new(ptr: *const u8) -> DwarfReader { - DwarfReader { ptr } - } - - /// Read a type T and then bump the pointer by that amount. - /// - /// DWARF streams are "packed", so all types must be read at align 1. - pub unsafe fn read(&mut self) -> T { - unsafe { - let result = self.ptr.cast::().read_unaligned(); - self.ptr = self.ptr.byte_add(size_of::()); - result - } - } - - /// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable Length Data". - pub unsafe fn read_uleb128(&mut self) -> u64 { - let mut shift: usize = 0; - let mut result: u64 = 0; - let mut byte: u8; - loop { - byte = unsafe { self.read::() }; - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - result - } - - pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: u32 = 0; - let mut result: u64 = 0; - let mut byte: u8; - loop { - byte = unsafe { self.read::() }; - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - // sign-extend - if shift < u64::BITS && (byte & 0x40) != 0 { - result |= (!0 as u64) << shift; - } - result as i64 - } -} diff --git a/library/std/src/sys/personality/dwarf/mod.rs b/library/std/src/sys/personality/dwarf/mod.rs new file mode 120000 index 0000000..1e96f35 --- /dev/null +++ b/library/std/src/sys/personality/dwarf/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/personality/dwarf/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/personality/dwarf/tests.rs b/library/std/src/sys/personality/dwarf/tests.rs deleted file mode 100644 index 1644f37..0000000 --- a/library/std/src/sys/personality/dwarf/tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::*; - -#[test] -fn dwarf_reader() { - let encoded: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 0xE5, 0x8E, 0x26, 0x9B, 0xF1, 0x59, 0xFF, 0xFF]; - - let mut reader = DwarfReader::new(encoded.as_ptr()); - - unsafe { - assert!(reader.read::() == u8::to_be(1u8)); - assert!(reader.read::() == u16::to_be(0x0203)); - assert!(reader.read::() == u32::to_be(0x04050607)); - - assert!(reader.read_uleb128() == 624485); - assert!(reader.read_sleb128() == -624485); - - assert!(reader.read::() == i8::to_be(-1)); - } -} diff --git a/library/std/src/sys/personality/dwarf/tests.rs b/library/std/src/sys/personality/dwarf/tests.rs new file mode 120000 index 0000000..97b8782 --- /dev/null +++ b/library/std/src/sys/personality/dwarf/tests.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/personality/dwarf/tests.rs \ No newline at end of file diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs deleted file mode 100644 index eabef92..0000000 --- a/library/std/src/sys/personality/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! This module contains the implementation of the `eh_personality` lang item. -//! -//! The actual implementation is heavily dependent on the target since Rust -//! tries to use the native stack unwinding mechanism whenever possible. -//! -//! This personality function is still required with `-C panic=abort` because -//! it is used to catch foreign exceptions from `extern "C-unwind"` and turn -//! them into aborts. -//! -//! Additionally, ARM EHABI uses the personality function when generating -//! backtraces. - -mod dwarf; - -#[cfg(not(any(test, doctest)))] -cfg_select! { - target_os = "emscripten" => { - mod emcc; - } - any(target_env = "msvc", target_family = "wasm", target_os = "motor") => { - // This is required by the compiler to exist (e.g., it's a lang item), - // but it's never actually called by the compiler because - // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the - // personality function that is always used. Hence this is just an - // aborting stub. - #[lang = "eh_personality"] - fn rust_eh_personality() { - core::intrinsics::abort() - } - } - any( - all(target_family = "windows", target_env = "gnu"), - target_os = "psp", - target_os = "xous", - target_os = "solid_asp3", - all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "nuttx")), - all(target_vendor = "fortanix", target_env = "sgx"), - ) => { - mod gcc; - } - _ => { - // Targets that don't support unwinding. - // - os=none ("bare metal" targets) - // - os=uefi - // - os=espidf - // - os=hermit - // - nvptx64-nvidia-cuda - // - arch=avr - } -} diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs new file mode 120000 index 0000000..0c1ddf5 --- /dev/null +++ b/library/std/src/sys/personality/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/personality/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/pipe/mod.rs b/library/std/src/sys/pipe/mod.rs deleted file mode 100644 index 8522896..0000000 --- a/library/std/src/sys/pipe/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -cfg_select! { - unix => { - mod unix; - pub use unix::{Pipe, pipe}; - } - windows => { - mod windows; - pub use windows::{Pipe, pipe}; - } - target_os = "motor" => { - mod motor; - pub use motor::{Pipe, pipe}; - } - _ => { - mod unsupported; - pub use unsupported::{Pipe, pipe}; - } -} diff --git a/library/std/src/sys/pipe/mod.rs b/library/std/src/sys/pipe/mod.rs new file mode 120000 index 0000000..53fc48e --- /dev/null +++ b/library/std/src/sys/pipe/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pipe/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/pipe/unsupported.rs b/library/std/src/sys/pipe/unsupported.rs deleted file mode 100644 index 1c5df47..0000000 --- a/library/std/src/sys/pipe/unsupported.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::fmt; -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; - -pub struct Pipe(!); - -#[inline] -pub fn pipe() -> io::Result<(Pipe, Pipe)> { - Err(io::Error::UNSUPPORTED_PLATFORM) -} - -impl Pipe { - pub fn try_clone(&self) -> io::Result { - self.0 - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - self.0 - } - - pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { - self.0 - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 - } - - pub fn is_read_vectored(&self) -> bool { - self.0 - } - - pub fn read_to_end(&self, _buf: &mut Vec) -> io::Result { - self.0 - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - self.0 - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - self.0 - } - - pub fn is_write_vectored(&self) -> bool { - self.0 - } - - pub fn diverge(&self) -> ! { - self.0 - } -} - -impl fmt::Debug for Pipe { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))] -mod unix_traits { - use super::Pipe; - use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; - use crate::sys::{FromInner, IntoInner}; - - impl AsRawFd for Pipe { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.0 - } - } - - impl AsFd for Pipe { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0 - } - } - - impl IntoRawFd for Pipe { - fn into_raw_fd(self) -> RawFd { - self.0 - } - } - - impl FromRawFd for Pipe { - unsafe fn from_raw_fd(_: RawFd) -> Self { - panic!("creating pipe on this platform is unsupported!") - } - } - - impl FromInner for Pipe { - fn from_inner(_: OwnedFd) -> Self { - panic!("creating pipe on this platform is unsupported!") - } - } - - impl IntoInner for Pipe { - fn into_inner(self) -> OwnedFd { - self.0 - } - } -} diff --git a/library/std/src/sys/pipe/unsupported.rs b/library/std/src/sys/pipe/unsupported.rs new file mode 120000 index 0000000..9f65be7 --- /dev/null +++ b/library/std/src/sys/pipe/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/pipe/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/platform_version/mod.rs b/library/std/src/sys/platform_version/mod.rs deleted file mode 100644 index 88896c9..0000000 --- a/library/std/src/sys/platform_version/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Runtime lookup of operating system / platform version. -//! -//! Related to [RFC 3750](https://github.com/rust-lang/rfcs/pull/3750), which -//! does version detection at compile-time. -//! -//! See also the `os_info` crate. - -#[cfg(target_vendor = "apple")] -mod darwin; - -// In the future, we could expand this module with: -// - `RtlGetVersion` on Windows. -// - `__system_property_get` on Android. diff --git a/library/std/src/sys/platform_version/mod.rs b/library/std/src/sys/platform_version/mod.rs new file mode 120000 index 0000000..6dc9f08 --- /dev/null +++ b/library/std/src/sys/platform_version/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/platform_version/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/process/env.rs b/library/std/src/sys/process/env.rs deleted file mode 100644 index e08b476..0000000 --- a/library/std/src/sys/process/env.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::collections::BTreeMap; -use crate::ffi::{OsStr, OsString}; -use crate::sys::process::EnvKey; -use crate::{env, fmt}; - -/// Stores a set of changes to an environment -#[derive(Clone, Default)] -pub struct CommandEnv { - clear: bool, - saw_path: bool, - vars: BTreeMap>, -} - -impl fmt::Debug for CommandEnv { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut debug_command_env = f.debug_struct("CommandEnv"); - debug_command_env.field("clear", &self.clear).field("vars", &self.vars); - debug_command_env.finish() - } -} - -impl CommandEnv { - // Capture the current environment with these changes applied - pub fn capture(&self) -> BTreeMap { - let mut result = BTreeMap::::new(); - if !self.clear { - for (k, v) in env::vars_os() { - result.insert(k.into(), v); - } - } - for (k, maybe_v) in &self.vars { - if let &Some(ref v) = maybe_v { - result.insert(k.clone(), v.clone()); - } else { - result.remove(k); - } - } - result - } - - pub fn is_unchanged(&self) -> bool { - !self.clear && self.vars.is_empty() - } - - pub fn capture_if_changed(&self) -> Option> { - if self.is_unchanged() { None } else { Some(self.capture()) } - } - - // The following functions build up changes - pub fn set(&mut self, key: &OsStr, value: &OsStr) { - let key = EnvKey::from(key); - self.maybe_saw_path(&key); - self.vars.insert(key, Some(value.to_owned())); - } - - pub fn remove(&mut self, key: &OsStr) { - let key = EnvKey::from(key); - self.maybe_saw_path(&key); - if self.clear { - self.vars.remove(&key); - } else { - self.vars.insert(key, None); - } - } - - pub fn clear(&mut self) { - self.clear = true; - self.vars.clear(); - } - - pub fn does_clear(&self) -> bool { - self.clear - } - - pub fn have_changed_path(&self) -> bool { - self.saw_path || self.clear - } - - fn maybe_saw_path(&mut self, key: &EnvKey) { - if !self.saw_path && key == "PATH" { - self.saw_path = true; - } - } - - pub fn iter(&self) -> CommandEnvs<'_> { - let iter = self.vars.iter(); - CommandEnvs { iter } - } -} - -#[derive(Debug)] -pub struct CommandEnvs<'a> { - iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, -} - -impl<'a> Iterator for CommandEnvs<'a> { - type Item = (&'a OsStr, Option<&'a OsStr>); - - fn next(&mut self) -> Option { - self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a> ExactSizeIterator for CommandEnvs<'a> { - fn len(&self) -> usize { - self.iter.len() - } - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} diff --git a/library/std/src/sys/process/env.rs b/library/std/src/sys/process/env.rs new file mode 120000 index 0000000..aa4324c --- /dev/null +++ b/library/std/src/sys/process/env.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/process/env.rs \ No newline at end of file diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs deleted file mode 100644 index 46f4ebf..0000000 --- a/library/std/src/sys/process/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -cfg_select! { - target_family = "unix" => { - mod unix; - use unix as imp; - } - target_os = "windows" => { - mod windows; - use windows as imp; - } - target_os = "uefi" => { - mod uefi; - use uefi as imp; - } - target_os = "motor" => { - mod motor; - use motor as imp; - } - _ => { - mod unsupported; - use unsupported as imp; - } -} - -// This module is shared by all platforms, but nearly all platforms except for -// the "normal" UNIX ones leave some of this code unused. -#[cfg_attr(not(target_os = "linux"), allow(dead_code))] -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, - getpid, read_output, -}; - -#[cfg(any( - all( - target_family = "unix", - not(any( - target_os = "espidf", - target_os = "horizon", - target_os = "vita", - target_os = "nuttx" - )) - ), - target_os = "windows", - target_os = "motor" -))] -pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec)> { - let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?; - - drop(pipes.stdin.take()); - let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); - match (pipes.stdout.take(), pipes.stderr.take()) { - (None, None) => {} - (Some(out), None) => { - let res = out.read_to_end(&mut stdout); - res.unwrap(); - } - (None, Some(err)) => { - let res = err.read_to_end(&mut stderr); - res.unwrap(); - } - (Some(out), Some(err)) => { - let res = read_output(out, &mut stdout, err, &mut stderr); - res.unwrap(); - } - } - - let status = process.wait()?; - Ok((status, stdout, stderr)) -} - -#[cfg(not(any( - all( - target_family = "unix", - not(any( - target_os = "espidf", - target_os = "horizon", - target_os = "vita", - target_os = "nuttx" - )) - ), - target_os = "windows", - target_os = "motor" -)))] -pub use imp::output; diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs new file mode 120000 index 0000000..390139c --- /dev/null +++ b/library/std/src/sys/process/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/process/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs deleted file mode 100644 index 9ed66a5..0000000 --- a/library/std/src/sys/process/unsupported.rs +++ /dev/null @@ -1,333 +0,0 @@ -use super::env::{CommandEnv, CommandEnvs}; -pub use crate::ffi::OsString as EnvKey; -use crate::ffi::{OsStr, OsString}; -use crate::num::NonZero; -use crate::path::Path; -use crate::process::StdioPipes; -use crate::sys::fs::File; -use crate::sys::unsupported; -use crate::{fmt, io}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - program: OsString, - args: Vec, - env: CommandEnv, - - cwd: Option, - stdin: Option, - stdout: Option, - stderr: Option, -} - -#[derive(Debug)] -pub enum Stdio { - Inherit, - Null, - MakePipe, - ParentStdout, - ParentStderr, - #[allow(dead_code)] // This variant exists only for the Debug impl - InheritFile(File), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - Command { - program: program.to_owned(), - args: vec![program.to_owned()], - env: Default::default(), - cwd: None, - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_owned()); - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(dir.to_owned()); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - pub fn get_program(&self) -> &OsStr { - &self.program - } - - pub fn get_args(&self) -> CommandArgs<'_> { - let mut iter = self.args.iter(); - iter.next(); - CommandArgs { iter } - } - - pub fn get_envs(&self) -> CommandEnvs<'_> { - self.env.iter() - } - - pub fn get_env_clear(&self) -> bool { - self.env.does_clear() - } - - pub fn get_current_dir(&self) -> Option<&Path> { - self.cwd.as_ref().map(|cs| Path::new(cs)) - } - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { - unsupported() -} - -impl From for Stdio { - fn from(pipe: ChildPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(_: io::Stdout) -> Stdio { - Stdio::ParentStdout - } -} - -impl From for Stdio { - fn from(_: io::Stderr) -> Stdio { - Stdio::ParentStderr - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - Stdio::InheritFile(file) - } -} - -impl fmt::Debug for Command { - // show all attributes - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - let mut debug_command = f.debug_struct("Command"); - debug_command.field("program", &self.program).field("args", &self.args); - if !self.env.is_unchanged() { - debug_command.field("env", &self.env); - } - - if self.cwd.is_some() { - debug_command.field("cwd", &self.cwd); - } - - if self.stdin.is_some() { - debug_command.field("stdin", &self.stdin); - } - if self.stdout.is_some() { - debug_command.field("stdout", &self.stdout); - } - if self.stderr.is_some() { - debug_command.field("stderr", &self.stderr); - } - - debug_command.finish() - } else { - if let Some(ref cwd) = self.cwd { - write!(f, "cd {cwd:?} && ")?; - } - if self.env.does_clear() { - write!(f, "env -i ")?; - // Altered env vars will be printed next, that should exactly work as expected. - } else { - // Removed env vars need the command to be wrapped in `env`. - let mut any_removed = false; - for (key, value_opt) in self.get_envs() { - if value_opt.is_none() { - if !any_removed { - write!(f, "env ")?; - any_removed = true; - } - write!(f, "-u {} ", key.to_string_lossy())?; - } - } - } - // Altered env vars can just be added in front of the program. - for (key, value_opt) in self.get_envs() { - if let Some(value) = value_opt { - write!(f, "{}={value:?} ", key.to_string_lossy())?; - } - } - if self.program != self.args[0] { - write!(f, "[{:?}] ", self.program)?; - } - write!(f, "{:?}", self.args[0])?; - - for arg in &self.args[1..] { - write!(f, " {:?}", arg)?; - } - Ok(()) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] -#[non_exhaustive] -pub struct ExitStatus(); - -impl ExitStatus { - pub fn exit_ok(&self) -> Result<(), ExitStatusError> { - Ok(()) - } - - pub fn code(&self) -> Option { - Some(0) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "") - } -} - -pub struct ExitStatusError(!); - -impl Clone for ExitStatusError { - fn clone(&self) -> ExitStatusError { - self.0 - } -} - -impl Copy for ExitStatusError {} - -impl PartialEq for ExitStatusError { - fn eq(&self, _other: &ExitStatusError) -> bool { - self.0 - } -} - -impl Eq for ExitStatusError {} - -impl fmt::Debug for ExitStatusError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } -} - -impl Into for ExitStatusError { - fn into(self) -> ExitStatus { - self.0 - } -} - -impl ExitStatusError { - pub fn code(self) -> Option> { - self.0 - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(u8); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(0); - pub const FAILURE: ExitCode = ExitCode(1); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -impl From for ExitCode { - fn from(code: u8) -> Self { - Self(code) - } -} - -pub struct Process(!); - -impl Process { - pub fn id(&self) -> u32 { - self.0 - } - - pub fn kill(&mut self) -> io::Result<()> { - self.0 - } - - pub fn wait(&mut self) -> io::Result { - self.0 - } - - pub fn try_wait(&mut self) -> io::Result> { - self.0 - } -} - -pub struct CommandArgs<'a> { - iter: crate::slice::Iter<'a, OsString>, -} - -impl<'a> Iterator for CommandArgs<'a> { - type Item = &'a OsStr; - fn next(&mut self) -> Option<&'a OsStr> { - self.iter.next().map(|os| &**os) - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a> ExactSizeIterator for CommandArgs<'a> { - fn len(&self) -> usize { - self.iter.len() - } - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -impl<'a> fmt::Debug for CommandArgs<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.iter.clone()).finish() - } -} - -pub type ChildPipe = crate::sys::pipe::Pipe; - -pub fn read_output( - out: ChildPipe, - _stdout: &mut Vec, - _err: ChildPipe, - _stderr: &mut Vec, -) -> io::Result<()> { - match out.diverge() {} -} - -pub fn getpid() -> u32 { - panic!("no pids on this platform") -} diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs new file mode 120000 index 0000000..7fa792f --- /dev/null +++ b/library/std/src/sys/process/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/process/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs deleted file mode 100644 index 894409b..0000000 --- a/library/std/src/sys/random/unsupported.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::ptr; - -pub fn fill_bytes(_: &mut [u8]) { - panic!("this target does not support random data generation"); -} - -pub fn hashmap_random_keys() -> (u64, u64) { - // Use allocation addresses for a bit of randomness. This isn't - // particularly secure, but there isn't really an alternative. - let stack = 0u8; - let heap = Box::new(0u8); - let k1 = ptr::from_ref(&stack).addr() as u64; - let k2 = ptr::from_ref(&*heap).addr() as u64; - (k1, k2) -} diff --git a/library/std/src/sys/random/unsupported.rs b/library/std/src/sys/random/unsupported.rs new file mode 120000 index 0000000..fca6e64 --- /dev/null +++ b/library/std/src/sys/random/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/random/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs deleted file mode 100644 index 86d0f3f..0000000 --- a/library/std/src/sys/stdio/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "wasi") => { - mod unix; - pub use unix::*; - } - target_os = "windows" => { - mod windows; - pub use windows::*; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::*; - } - target_os = "motor" => { - mod motor; - pub use motor::*; - } - target_os = "solid_asp3" => { - mod solid; - pub use solid::*; - } - target_os = "teeos" => { - mod teeos; - pub use teeos::*; - } - target_os = "trusty" => { - mod trusty; - pub use trusty::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - target_os = "vexos" => { - mod vexos; - pub use vexos::*; - } - target_os = "xous" => { - mod xous; - pub use xous::*; - } - target_os = "zkvm" => { - mod zkvm; - pub use zkvm::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } -} diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs new file mode 120000 index 0000000..d8aeca4 --- /dev/null +++ b/library/std/src/sys/stdio/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/stdio/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/stdio/unsupported.rs b/library/std/src/sys/stdio/unsupported.rs deleted file mode 100644 index 177264f..0000000 --- a/library/std/src/sys/stdio/unsupported.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; - -pub struct Stdin; -pub struct Stdout; -pub type Stderr = Stdout; - -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl io::Read for Stdin { - #[inline] - fn read(&mut self, _buf: &mut [u8]) -> io::Result { - Ok(0) - } - - #[inline] - fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn read_vectored(&mut self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - Ok(0) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - // Do not force `Chain` or `Chain` to use vectored - // reads, unless the other reader is vectored. - false - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } - } - - #[inline] - fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - if cursor.capacity() != 0 { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } - } - - #[inline] - fn read_to_end(&mut self, _buf: &mut Vec) -> io::Result { - Ok(0) - } - - #[inline] - fn read_to_string(&mut self, _buf: &mut String) -> io::Result { - Ok(0) - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout - } -} - -impl io::Write for Stdout { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum(); - Ok(total_len) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - #[inline] - fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> { - Ok(()) - } - - #[inline] - fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - Ok(()) - } - - // Keep the default write_fmt so the `fmt::Arguments` are still evaluated. - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = 0; - -pub fn is_ebadf(_err: &io::Error) -> bool { - true -} - -pub fn panic_output() -> Option> { - None -} diff --git a/library/std/src/sys/stdio/unsupported.rs b/library/std/src/sys/stdio/unsupported.rs new file mode 120000 index 0000000..c56d5ba --- /dev/null +++ b/library/std/src/sys/stdio/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/stdio/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs deleted file mode 100644 index 83cf0ae..0000000 --- a/library/std/src/sys/sync/condvar/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -cfg_select! { - any( - all(target_os = "windows", not(target_vendor="win7")), - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - target_os = "motor", - target_os = "fuchsia", - all(target_family = "wasm", target_feature = "atomics"), - target_os = "hermit", - ) => { - mod futex; - pub use futex::Condvar; - } - any( - target_family = "unix", - target_os = "teeos", - ) => { - mod pthread; - pub use pthread::Condvar; - } - all(target_os = "windows", target_vendor = "win7") => { - mod windows7; - pub use windows7::Condvar; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::Condvar; - } - target_os = "solid_asp3" => { - mod itron; - pub use itron::Condvar; - } - target_os = "xous" => { - mod xous; - pub use xous::Condvar; - } - _ => { - mod no_threads; - pub use no_threads::Condvar; - } -} diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs new file mode 120000 index 0000000..eb01345 --- /dev/null +++ b/library/std/src/sys/sync/condvar/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/condvar/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs deleted file mode 100644 index 18d97d4..0000000 --- a/library/std/src/sys/sync/condvar/no_threads.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::sys::sync::Mutex; -use crate::thread::sleep; -use crate::time::Duration; - -pub struct Condvar {} - -impl Condvar { - #[inline] - pub const fn new() -> Condvar { - Condvar {} - } - - #[inline] - pub fn notify_one(&self) {} - - #[inline] - pub fn notify_all(&self) {} - - pub unsafe fn wait(&self, _mutex: &Mutex) { - panic!("condvar wait not supported") - } - - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, dur: Duration) -> bool { - sleep(dur); - false - } -} diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs new file mode 120000 index 0000000..f31e2fd --- /dev/null +++ b/library/std/src/sys/sync/condvar/no_threads.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/condvar/no_threads.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs deleted file mode 100644 index 0691e96..0000000 --- a/library/std/src/sys/sync/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod condvar; -mod mutex; -mod once; -mod once_box; -mod rwlock; -mod thread_parking; - -pub use condvar::Condvar; -pub use mutex::Mutex; -pub use once::{Once, OnceState}; -#[allow(unused)] // Only used on some platforms. -use once_box::OnceBox; -pub use rwlock::RwLock; -pub use thread_parking::Parker; diff --git a/library/std/src/sys/sync/mod.rs b/library/std/src/sys/sync/mod.rs new file mode 120000 index 0000000..b1a684c --- /dev/null +++ b/library/std/src/sys/sync/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs deleted file mode 100644 index e3d6ad1..0000000 --- a/library/std/src/sys/sync/mutex/mod.rs +++ /dev/null @@ -1,47 +0,0 @@ -cfg_select! { - any( - all(target_os = "windows", not(target_vendor = "win7")), - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "motor", - target_os = "dragonfly", - all(target_family = "wasm", target_feature = "atomics"), - target_os = "hermit", - ) => { - mod futex; - pub use futex::Mutex; - } - target_os = "fuchsia" => { - mod fuchsia; - pub use fuchsia::Mutex; - } - any( - target_family = "unix", - target_os = "teeos", - ) => { - mod pthread; - pub use pthread::Mutex; - } - all(target_os = "windows", target_vendor = "win7") => { - mod windows7; - pub use windows7::{Mutex, raw}; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::Mutex; - } - target_os = "solid_asp3" => { - mod itron; - pub use itron::Mutex; - } - target_os = "xous" => { - mod xous; - pub use xous::Mutex; - } - _ => { - mod no_threads; - pub use no_threads::Mutex; - } -} diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs new file mode 120000 index 0000000..87606bf --- /dev/null +++ b/library/std/src/sys/sync/mutex/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/mutex/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs deleted file mode 100644 index 57c78f4..0000000 --- a/library/std/src/sys/sync/mutex/no_threads.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::cell::Cell; - -pub struct Mutex { - // This platform has no threads, so we can use a Cell here. - locked: Cell, -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} // no threads on this platform - -impl Mutex { - #[inline] - pub const fn new() -> Mutex { - Mutex { locked: Cell::new(false) } - } - - #[inline] - pub fn lock(&self) { - assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex"); - } - - #[inline] - pub unsafe fn unlock(&self) { - self.locked.set(false); - } - - #[inline] - pub fn try_lock(&self) -> bool { - self.locked.replace(true) == false - } -} diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs new file mode 120000 index 0000000..18b7958 --- /dev/null +++ b/library/std/src/sys/sync/mutex/no_threads.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/mutex/no_threads.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs deleted file mode 100644 index 5796c6d..0000000 --- a/library/std/src/sys/sync/once/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ -// A "once" is a relatively simple primitive, and it's also typically provided -// by the OS as well (see `pthread_once` or `InitOnceExecuteOnce`). The OS -// primitives, however, tend to have surprising restrictions, such as the Unix -// one doesn't allow an argument to be passed to the function. -// -// As a result, we end up implementing it ourselves in the standard library. -// This also gives us the opportunity to optimize the implementation a bit which -// should help the fast path on call sites. - -cfg_select! { - any( - all(target_os = "windows", not(target_vendor="win7")), - target_os = "linux", - target_os = "android", - all(target_family = "wasm", target_feature = "atomics"), - target_os = "freebsd", - target_os = "motor", - target_os = "openbsd", - target_os = "dragonfly", - target_os = "fuchsia", - target_os = "hermit", - ) => { - mod futex; - pub use futex::{Once, OnceState}; - } - any( - windows, - target_family = "unix", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "solid_asp3", - target_os = "xous", - ) => { - mod queue; - pub use queue::{Once, OnceState}; - } - _ => { - mod no_threads; - pub use no_threads::{Once, OnceState}; - } -} diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs new file mode 120000 index 0000000..c142705 --- /dev/null +++ b/library/std/src/sys/sync/once/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/once/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs deleted file mode 100644 index 42fe241..0000000 --- a/library/std/src/sys/sync/once/no_threads.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::cell::Cell; -use crate::sync as public; -use crate::sync::once::OnceExclusiveState; - -pub struct Once { - state: Cell, -} - -pub struct OnceState { - poisoned: bool, - set_state_to: Cell, -} - -#[derive(Clone, Copy, PartialEq, Eq)] -enum State { - Incomplete, - Poisoned, - Running, - Complete, -} - -struct CompletionGuard<'a> { - state: &'a Cell, - set_state_on_drop_to: State, -} - -impl<'a> Drop for CompletionGuard<'a> { - fn drop(&mut self) { - self.state.set(self.set_state_on_drop_to); - } -} - -// Safety: threads are not supported on this platform. -unsafe impl Sync for Once {} - -impl Once { - #[inline] - pub const fn new() -> 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 - } - - #[inline] - pub(crate) fn state(&mut self) -> OnceExclusiveState { - match self.state.get() { - State::Incomplete => OnceExclusiveState::Incomplete, - State::Poisoned => OnceExclusiveState::Poisoned, - State::Complete => OnceExclusiveState::Complete, - _ => unreachable!("invalid Once state"), - } - } - - #[inline] - pub(crate) fn set_state(&mut self, new_state: OnceExclusiveState) { - self.state.set(match new_state { - OnceExclusiveState::Incomplete => State::Incomplete, - OnceExclusiveState::Poisoned => State::Poisoned, - OnceExclusiveState::Complete => State::Complete, - }); - } - - #[cold] - #[track_caller] - pub fn wait(&self, _ignore_poisoning: bool) { - panic!("not implementable on this target"); - } - - #[cold] - #[track_caller] - pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) { - let state = self.state.get(); - match state { - State::Poisoned if !ignore_poisoning => { - // Panic to propagate the poison. - panic!("Once instance has previously been poisoned"); - } - State::Incomplete | State::Poisoned => { - self.state.set(State::Running); - // `guard` will set the new state on drop. - let mut guard = - CompletionGuard { state: &self.state, set_state_on_drop_to: State::Poisoned }; - // Run the function, letting it know if we're poisoned or not. - let f_state = public::OnceState { - inner: OnceState { - poisoned: state == State::Poisoned, - set_state_to: Cell::new(State::Complete), - }, - }; - f(&f_state); - guard.set_state_on_drop_to = f_state.inner.set_state_to.get(); - } - State::Running => { - panic!("one-time initialization may not be performed recursively"); - } - State::Complete => {} - } - } -} - -impl OnceState { - #[inline] - pub fn is_poisoned(&self) -> bool { - self.poisoned - } - - #[inline] - pub fn poison(&self) { - self.set_state_to.set(State::Poisoned) - } -} diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs new file mode 120000 index 0000000..d289b30 --- /dev/null +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/once/no_threads.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs deleted file mode 100644 index 088f51a..0000000 --- a/library/std/src/sys/sync/once_box.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! A racily-initialized alternative to `OnceLock>`. -//! -//! This is used to implement synchronization primitives that need allocation, -//! like the pthread versions. - -#![allow(dead_code)] // Only used on some platforms. - -use crate::mem::replace; -use crate::pin::Pin; -use crate::ptr::null_mut; -use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sync::atomic::{Atomic, AtomicPtr}; - -pub(crate) struct OnceBox { - ptr: Atomic<*mut T>, -} - -impl OnceBox { - #[inline] - pub const fn new() -> Self { - Self { ptr: AtomicPtr::new(null_mut()) } - } - - /// Gets access to the value, assuming it is already initialized and this - /// initialization has been observed by the current thread. - /// - /// Since all modifications to the pointer have already been observed, the - /// pointer load in this function can be performed with relaxed ordering, - /// potentially allowing the optimizer to turn code like this: - /// ```rust, ignore - /// once_box.get_or_init(|| Box::pin(42)); - /// unsafe { once_box.get_unchecked() } - /// ``` - /// into - /// ```rust, ignore - /// once_box.get_or_init(|| Box::pin(42)) - /// ``` - /// - /// # Safety - /// This causes undefined behavior if the assumption above is violated. - #[inline] - pub unsafe fn get_unchecked(&self) -> Pin<&T> { - unsafe { Pin::new_unchecked(&*self.ptr.load(Relaxed)) } - } - - #[inline] - pub fn get_or_init(&self, f: impl FnOnce() -> Pin>) -> Pin<&T> { - let ptr = self.ptr.load(Acquire); - match unsafe { ptr.as_ref() } { - Some(val) => unsafe { Pin::new_unchecked(val) }, - None => self.initialize(f), - } - } - - #[inline] - pub fn take(&mut self) -> Option>> { - let ptr = replace(self.ptr.get_mut(), null_mut()); - if !ptr.is_null() { Some(unsafe { Pin::new_unchecked(Box::from_raw(ptr)) }) } else { None } - } - - #[cold] - fn initialize(&self, f: impl FnOnce() -> Pin>) -> Pin<&T> { - let new_ptr = Box::into_raw(unsafe { Pin::into_inner_unchecked(f()) }); - match self.ptr.compare_exchange(null_mut(), new_ptr, Release, Acquire) { - Ok(_) => unsafe { Pin::new_unchecked(&*new_ptr) }, - Err(ptr) => { - // Lost the race to another thread. - // Drop the value we created, and use the one from the other thread instead. - drop(unsafe { Box::from_raw(new_ptr) }); - unsafe { Pin::new_unchecked(&*ptr) } - } - } - } -} - -unsafe impl Send for OnceBox {} -unsafe impl Sync for OnceBox {} - -impl Drop for OnceBox { - fn drop(&mut self) { - self.take(); - } -} diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs new file mode 120000 index 0000000..60e4913 --- /dev/null +++ b/library/std/src/sys/sync/once_box.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/once_box.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs deleted file mode 100644 index 8603fca..0000000 --- a/library/std/src/sys/sync/rwlock/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -cfg_select! { - any( - all(target_os = "windows", not(target_vendor = "win7")), - target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - target_os = "fuchsia", - all(target_family = "wasm", target_feature = "atomics"), - target_os = "hermit", - target_os = "motor", - ) => { - mod futex; - pub use futex::RwLock; - } - any( - target_family = "unix", - all(target_os = "windows", target_vendor = "win7"), - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "xous", - target_os = "teeos", - ) => { - mod queue; - pub use queue::RwLock; - } - target_os = "solid_asp3" => { - mod solid; - pub use solid::RwLock; - } - _ => { - mod no_threads; - pub use no_threads::RwLock; - } -} diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs new file mode 120000 index 0000000..2621b38 --- /dev/null +++ b/library/std/src/sys/sync/rwlock/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/rwlock/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs deleted file mode 100644 index 573d0d6..0000000 --- a/library/std/src/sys/sync/rwlock/no_threads.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::cell::Cell; - -pub struct RwLock { - // This platform has no threads, so we can use a Cell here. - mode: Cell, -} - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} // no threads on this platform - -impl RwLock { - #[inline] - pub const fn new() -> RwLock { - RwLock { mode: Cell::new(0) } - } - - #[inline] - pub fn read(&self) { - let m = self.mode.get(); - if m >= 0 { - self.mode.set(m + 1); - } else { - rtabort!("rwlock locked for writing"); - } - } - - #[inline] - pub fn try_read(&self) -> bool { - let m = self.mode.get(); - if m >= 0 { - self.mode.set(m + 1); - true - } else { - false - } - } - - #[inline] - pub fn write(&self) { - if self.mode.replace(-1) != 0 { - rtabort!("rwlock locked for reading") - } - } - - #[inline] - pub fn try_write(&self) -> bool { - if self.mode.get() == 0 { - self.mode.set(-1); - true - } else { - false - } - } - - #[inline] - pub unsafe fn read_unlock(&self) { - self.mode.set(self.mode.get() - 1); - } - - #[inline] - pub unsafe fn write_unlock(&self) { - assert_eq!(self.mode.replace(0), -1); - } - - #[inline] - pub unsafe fn downgrade(&self) { - assert_eq!(self.mode.replace(1), -1); - } -} diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs new file mode 120000 index 0000000..6feab01 --- /dev/null +++ b/library/std/src/sys/sync/rwlock/no_threads.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/rwlock/no_threads.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs deleted file mode 100644 index 9d5a0a9..0000000 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ /dev/null @@ -1,49 +0,0 @@ -cfg_select! { - any( - all(target_os = "windows", not(target_vendor = "win7")), - target_os = "linux", - target_os = "android", - all(target_family = "wasm", target_feature = "atomics"), - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - target_os = "fuchsia", - target_os = "motor", - target_os = "hermit", - ) => { - mod futex; - pub use futex::Parker; - } - any( - target_os = "netbsd", - all(target_vendor = "fortanix", target_env = "sgx"), - target_os = "solid_asp3", - ) => { - mod id; - pub use id::Parker; - } - target_vendor = "win7" => { - mod windows7; - pub use windows7::Parker; - } - all(target_vendor = "apple", not(miri)) => { - // Doesn't work in Miri, see . - mod darwin; - pub use darwin::Parker; - } - target_os = "xous" => { - mod xous; - pub use xous::Parker; - } - any( - target_family = "unix", - target_os = "teeos", - ) => { - mod pthread; - pub use pthread::Parker; - } - _ => { - mod unsupported; - pub use unsupported::Parker; - } -} diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs new file mode 120000 index 0000000..535e453 --- /dev/null +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/thread_parking/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/sync/thread_parking/unsupported.rs b/library/std/src/sys/sync/thread_parking/unsupported.rs deleted file mode 100644 index 197078b..0000000 --- a/library/std/src/sys/sync/thread_parking/unsupported.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::pin::Pin; -use crate::time::Duration; - -pub struct Parker {} - -impl Parker { - pub unsafe fn new_in_place(_parker: *mut Parker) {} - pub unsafe fn park(self: Pin<&Self>) {} - pub unsafe fn park_timeout(self: Pin<&Self>, _dur: Duration) {} - pub fn unpark(self: Pin<&Self>) {} -} diff --git a/library/std/src/sys/sync/thread_parking/unsupported.rs b/library/std/src/sys/sync/thread_parking/unsupported.rs new file mode 120000 index 0000000..eb0b25a --- /dev/null +++ b/library/std/src/sys/sync/thread_parking/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/sync/thread_parking/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs deleted file mode 100644 index 9816981..0000000 --- a/library/std/src/sys/thread/mod.rs +++ /dev/null @@ -1,154 +0,0 @@ -cfg_select! { - target_os = "hermit" => { - mod hermit; - pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{current_os_id, set_name}; - } - target_os = "motor" => { - mod motor; - pub use motor::*; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - - // SGX should protect in-enclave data from outside attackers, so there - // must not be any data leakage to the OS, particularly no 1-1 mapping - // between SGX thread names and OS thread names. Hence `set_name` is - // intentionally a no-op. - // - // Note that the internally visible SGX thread name is already provided - // by the platform-agnostic Rust thread code. This can be observed in - // the [`std::thread::tests::test_named_thread`] test, which succeeds - // as-is with the SGX target. - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{available_parallelism, set_name}; - } - target_os = "solid_asp3" => { - mod solid; - pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{available_parallelism, current_os_id, set_name}; - } - target_os = "teeos" => { - mod teeos; - pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{available_parallelism, current_os_id, set_name}; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::{available_parallelism, sleep}; - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; - } - any(target_family = "unix", target_os = "wasi") => { - mod unix; - pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - #[cfg(not(any( - target_env = "newlib", - target_os = "l4re", - target_os = "emscripten", - target_os = "redox", - target_os = "hurd", - target_os = "aix", - target_os = "wasi", - )))] - pub use unix::set_name; - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "solaris", - target_os = "illumos", - target_os = "dragonfly", - target_os = "hurd", - target_os = "vxworks", - target_os = "wasi", - target_vendor = "apple", - ))] - pub use unix::sleep_until; - #[expect(dead_code)] - mod unsupported; - #[cfg(any( - target_env = "newlib", - target_os = "l4re", - target_os = "emscripten", - target_os = "redox", - target_os = "hurd", - target_os = "aix", - target_os = "wasi", - ))] - pub use unsupported::set_name; - } - target_os = "vexos" => { - mod vexos; - pub use vexos::{sleep, sleep_until, yield_now}; - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE}; - } - all(target_family = "wasm", target_feature = "atomics") => { - mod wasm; - pub use wasm::sleep; - - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; - } - target_os = "windows" => { - mod windows; - pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - } - target_os = "xous" => { - mod xous; - pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - - #[expect(dead_code)] - mod unsupported; - pub use unsupported::{current_os_id, set_name}; - } - _ => { - mod unsupported; - pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; - } -} - -#[cfg(not(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "solaris", - target_os = "illumos", - target_os = "dragonfly", - target_os = "hurd", - target_os = "vxworks", - target_os = "wasi", - target_vendor = "apple", - target_os = "motor", - target_os = "vexos" -)))] -pub fn sleep_until(deadline: crate::time::Instant) { - use crate::time::Instant; - - // The clock source used for `sleep` might not be the same used for `Instant`. - // Since this function *must not* return before the deadline, we recheck the - // time after every call to `sleep`. See #149935 for an example of this - // occurring on older Windows systems. - while let Some(delay) = deadline.checked_duration_since(Instant::now()) { - // Sleep for the estimated time remaining until the deadline. - // - // If your system has a better way of estimating the delay time or - // provides a way to sleep until an absolute time, specialize this - // function for your system. - sleep(delay); - } -} diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs new file mode 120000 index 0000000..6a9e354 --- /dev/null +++ b/library/std/src/sys/thread/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/thread/unsupported.rs b/library/std/src/sys/thread/unsupported.rs deleted file mode 100644 index d633e83..0000000 --- a/library/std/src/sys/thread/unsupported.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::ffi::CStr; -use crate::io; -use crate::num::NonZero; -use crate::thread::ThreadInit; -use crate::time::Duration; - -// Silence dead code warnings for the otherwise unused ThreadInit::init() call. -#[expect(dead_code)] -fn dummy_init_call(init: Box) { - drop(init.init()); -} - -pub struct Thread(!); - -pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _init: Box) -> io::Result { - Err(io::Error::UNSUPPORTED_PLATFORM) - } - - pub fn join(self) { - self.0 - } -} - -pub fn available_parallelism() -> io::Result> { - Err(io::Error::UNKNOWN_THREAD_COUNT) -} - -pub fn current_os_id() -> Option { - None -} - -pub fn yield_now() { - // do nothing -} - -pub fn set_name(_name: &CStr) { - // nope -} - -pub fn sleep(_dur: Duration) { - panic!("can't sleep"); -} diff --git a/library/std/src/sys/thread/unsupported.rs b/library/std/src/sys/thread/unsupported.rs new file mode 120000 index 0000000..27cedcb --- /dev/null +++ b/library/std/src/sys/thread/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread/unsupported.rs \ No newline at end of file diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs deleted file mode 100644 index 27a589a..0000000 --- a/library/std/src/sys/thread_local/no_threads.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! On some targets like wasm there's no threads, so no need to generate -//! thread locals and we can instead just use plain statics! - -use crate::cell::{Cell, UnsafeCell}; -use crate::mem::MaybeUninit; -use crate::ptr; - -#[doc(hidden)] -#[allow_internal_unstable(thread_local_internals)] -#[allow_internal_unsafe] -#[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semiopaque"] -pub macro thread_local_inner { - // used to generate the `LocalKey` value for const-initialized thread locals - (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ - const __RUST_STD_INTERNAL_INIT: $t = $init; - - // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed. - unsafe { - $crate::thread::LocalKey::new(|_| { - $(#[$align_attr])* - static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::EagerStorage<$t> = - $crate::thread::local_impl::EagerStorage { value: __RUST_STD_INTERNAL_INIT }; - &__RUST_STD_INTERNAL_VAL.value - }) - } - }}, - - // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ - #[inline] - fn __rust_std_internal_init_fn() -> $t { $init } - - unsafe { - $crate::thread::LocalKey::new(|__rust_std_internal_init| { - $(#[$align_attr])* - static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new(); - __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn) - }) - } - }}, -} - -#[allow(missing_debug_implementations)] -#[repr(transparent)] // Required for correctness of `#[rustc_align_static]` -pub struct EagerStorage { - pub value: T, -} - -// SAFETY: the target doesn't have threads. -unsafe impl Sync for EagerStorage {} - -#[derive(Clone, Copy, PartialEq, Eq)] -enum State { - Initial, - Alive, - Destroying, -} - -#[allow(missing_debug_implementations)] -#[repr(C)] -pub struct LazyStorage { - // This field must be first, for correctness of `#[rustc_align_static]` - value: UnsafeCell>, - state: Cell, -} - -impl LazyStorage { - pub const fn new() -> LazyStorage { - LazyStorage { - value: UnsafeCell::new(MaybeUninit::uninit()), - state: Cell::new(State::Initial), - } - } - - /// Gets a pointer to the TLS value, potentially initializing it with the - /// provided parameters. - /// - /// The resulting pointer may not be used after reentrant inialialization - /// has occurred. - #[inline] - pub fn get(&'static self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - if self.state.get() == State::Alive { - self.value.get() as *const T - } else { - self.initialize(i, f) - } - } - - #[cold] - fn initialize(&'static self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - let value = i.and_then(Option::take).unwrap_or_else(f); - - // Destroy the old value if it is initialized - // FIXME(#110897): maybe panic on recursive initialization. - if self.state.get() == State::Alive { - self.state.set(State::Destroying); - // Safety: we check for no initialization during drop below - unsafe { - ptr::drop_in_place(self.value.get() as *mut T); - } - self.state.set(State::Initial); - } - - // Guard against initialization during drop - if self.state.get() == State::Destroying { - panic!("Attempted to initialize thread-local while it is being dropped"); - } - - unsafe { - self.value.get().write(MaybeUninit::new(value)); - } - self.state.set(State::Alive); - - self.value.get() as *const T - } -} - -// SAFETY: the target doesn't have threads. -unsafe impl Sync for LazyStorage {} - -#[rustc_macro_transparency = "semiopaque"] -pub(crate) macro local_pointer { - () => {}, - ($vis:vis static $name:ident; $($rest:tt)*) => { - $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); - $crate::sys::thread_local::local_pointer! { $($rest)* } - }, -} - -pub(crate) struct LocalPointer { - p: Cell<*mut ()>, -} - -impl LocalPointer { - pub const fn __new() -> LocalPointer { - LocalPointer { p: Cell::new(ptr::null_mut()) } - } - - pub fn get(&self) -> *mut () { - self.p.get() - } - - pub fn set(&self, p: *mut ()) { - self.p.set(p) - } -} - -// SAFETY: the target doesn't have threads. -unsafe impl Sync for LocalPointer {} diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs new file mode 120000 index 0000000..21e52fc --- /dev/null +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread_local/no_threads.rs \ No newline at end of file diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs deleted file mode 100644 index 3f06c9b..0000000 --- a/library/std/src/sys/thread_local/os.rs +++ /dev/null @@ -1,289 +0,0 @@ -use super::key::{Key, LazyKey, get, set}; -use super::{abort_on_dtor_unwind, guard}; -use crate::alloc::{self, GlobalAlloc, Layout, System}; -use crate::cell::Cell; -use crate::marker::PhantomData; -use crate::mem::ManuallyDrop; -use crate::ops::Deref; -use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; -use crate::ptr::{self, NonNull}; - -#[doc(hidden)] -#[allow_internal_unstable(thread_local_internals)] -#[allow_internal_unsafe] -#[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semiopaque"] -pub macro thread_local_inner { - // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user - // provided type or type alias with a matching name. Please update the shadowing test in - // `tests/thread.rs` if these types are renamed. - - // used to generate the `LocalKey` value for `thread_local!`. - (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{ - #[inline] - fn __rust_std_internal_init_fn() -> $t { $init } - - // NOTE: this cannot import `LocalKey` or `Storage` with a `use` because that can shadow - // user provided type or type alias with a matching name. Please update the shadowing test - // in `tests/thread.rs` if these types are renamed. - unsafe { - $crate::thread::LocalKey::new(|__rust_std_internal_init| { - static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::Storage<$t, { - $({ - // Ensure that attributes have valid syntax - // and that the proper feature gate is enabled - $(#[$($align_attr)*])+ - #[allow(unused)] - static DUMMY: () = (); - })? - - #[allow(unused_mut)] - let mut final_align = $crate::thread::local_impl::value_align::<$t>(); - $($($crate::thread::local_impl::thread_local_inner!(@align final_align, $($align_attr)*);)+)? - final_align - }> - = $crate::thread::local_impl::Storage::new(); - __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn) - }) - } - }}, - - // process a single `rustc_align_static` attribute - (@align $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => { - let new_align: $crate::primitive::usize = $($align)*; - if new_align > $final_align { - $final_align = new_align; - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - // process a single `cfg_attr` attribute - // by translating it into a `cfg`ed block and recursing. - // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate - - (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg(true)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg(false)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, - - (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { - #[cfg($cfg_pred)] - { - $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); - } - - $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? - }, -} - -/// Use a regular global static to store this key; the state provided will then be -/// thread-local. -/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::`. -#[allow(missing_debug_implementations)] -pub struct Storage { - key: LazyKey, - marker: PhantomData>, -} - -unsafe impl Sync for Storage {} - -#[repr(C)] -struct Value { - // This field must be first, for correctness of `#[rustc_align_static]` - value: T, - // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`. - key: Key, -} - -pub const fn value_align() -> usize { - crate::mem::align_of::>() -} - -/// Equivalent to `Box, System>`, but potentially over-aligned. -struct AlignedSystemBox { - ptr: NonNull>, -} - -impl AlignedSystemBox { - #[inline] - fn new(v: Value) -> Self { - let layout = Layout::new::>().align_to(ALIGN).unwrap(); - - // We use the System allocator here to avoid interfering with a potential - // Global allocator using thread-local storage. - let ptr: *mut Value = (unsafe { System.alloc(layout) }).cast(); - let Some(ptr) = NonNull::new(ptr) else { - alloc::handle_alloc_error(layout); - }; - unsafe { ptr.write(v) }; - Self { ptr } - } - - #[inline] - fn into_raw(b: Self) -> *mut Value { - let md = ManuallyDrop::new(b); - md.ptr.as_ptr() - } - - #[inline] - unsafe fn from_raw(ptr: *mut Value) -> Self { - Self { ptr: unsafe { NonNull::new_unchecked(ptr) } } - } -} - -impl Deref for AlignedSystemBox { - type Target = Value; - - #[inline] - fn deref(&self) -> &Self::Target { - unsafe { &*(self.ptr.as_ptr()) } - } -} - -impl Drop for AlignedSystemBox { - #[inline] - fn drop(&mut self) { - let layout = Layout::new::>().align_to(ALIGN).unwrap(); - - unsafe { - let unwind_result = catch_unwind(AssertUnwindSafe(|| self.ptr.drop_in_place())); - System.dealloc(self.ptr.as_ptr().cast(), layout); - if let Err(payload) = unwind_result { - resume_unwind(payload); - } - } - } -} - -impl Storage { - pub const fn new() -> Storage { - Storage { key: LazyKey::new(Some(destroy_value::)), marker: PhantomData } - } - - /// Gets a pointer to the TLS value, potentially initializing it with the - /// provided parameters. If the TLS variable has been destroyed, a null - /// pointer is returned. - /// - /// The resulting pointer may not be used after reentrant inialialization - /// or thread destruction has occurred. - pub fn get(&'static self, i: Option<&mut Option>, f: impl FnOnce() -> T) -> *const T { - let key = self.key.force(); - let ptr = unsafe { get(key) as *mut Value }; - if ptr.addr() > 1 { - // SAFETY: the check ensured the pointer is safe (its destructor - // is not running) + it is coming from a trusted source (self). - unsafe { &(*ptr).value } - } else { - // SAFETY: trivially correct. - unsafe { Self::try_initialize(key, ptr, i, f) } - } - } - - /// # Safety - /// * `key` must be the result of calling `self.key.force()` - /// * `ptr` must be the current value associated with `key`. - unsafe fn try_initialize( - key: Key, - ptr: *mut Value, - i: Option<&mut Option>, - f: impl FnOnce() -> T, - ) -> *const T { - if ptr.addr() == 1 { - // destructor is running - return ptr::null(); - } - - let value = AlignedSystemBox::::new(Value { - value: i.and_then(Option::take).unwrap_or_else(f), - key, - }); - let ptr = AlignedSystemBox::into_raw(value); - - // SAFETY: - // * key came from a `LazyKey` and is thus correct. - // * `ptr` is a correct pointer that can be destroyed by the key destructor. - // * the value is stored under the key that it contains. - let old = unsafe { - let old = get(key) as *mut Value; - set(key, ptr as *mut u8); - old - }; - - if !old.is_null() { - // If the variable was recursively initialized, drop the old value. - // SAFETY: We cannot be inside a `LocalKey::with` scope, as the - // initializer has already returned and the next scope only starts - // after we return the pointer. Therefore, there can be no references - // to the old value. - drop(unsafe { AlignedSystemBox::::from_raw(old) }); - } - - // SAFETY: We just created this value above. - unsafe { &(*ptr).value } - } -} - -unsafe extern "C" fn destroy_value(ptr: *mut u8) { - // SAFETY: - // - // The OS TLS ensures that this key contains a null value when this - // destructor starts to run. We set it back to a sentinel value of 1 to - // ensure that any future calls to `get` for this thread will return - // `None`. - // - // Note that to prevent an infinite loop we reset it back to null right - // before we return from the destructor ourselves. - abort_on_dtor_unwind(|| { - let ptr = unsafe { AlignedSystemBox::::from_raw(ptr as *mut Value) }; - let key = ptr.key; - // SAFETY: `key` is the TLS key `ptr` was stored under. - unsafe { set(key, ptr::without_provenance_mut(1)) }; - drop(ptr); - // SAFETY: `key` is the TLS key `ptr` was stored under. - unsafe { set(key, ptr::null_mut()) }; - // Make sure that the runtime cleanup will be performed - // after the next round of TLS destruction. - guard::enable(); - }); -} - -#[rustc_macro_transparency = "semiopaque"] -pub(crate) macro local_pointer { - () => {}, - ($vis:vis static $name:ident; $($rest:tt)*) => { - $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new(); - $crate::sys::thread_local::local_pointer! { $($rest)* } - }, -} - -pub(crate) struct LocalPointer { - key: LazyKey, -} - -impl LocalPointer { - pub const fn __new() -> LocalPointer { - LocalPointer { key: LazyKey::new(None) } - } - - pub fn get(&'static self) -> *mut () { - unsafe { get(self.key.force()) as *mut () } - } - - pub fn set(&'static self, p: *mut ()) { - unsafe { set(self.key.force(), p as *mut u8) } - } -} diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs new file mode 120000 index 0000000..d4f5fc4 --- /dev/null +++ b/library/std/src/sys/thread_local/os.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread_local/os.rs \ No newline at end of file diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs deleted file mode 100644 index 6cd1850..0000000 --- a/library/std/src/sys/time/mod.rs +++ /dev/null @@ -1,53 +0,0 @@ -cfg_select! { - target_os = "hermit" => { - mod hermit; - use hermit as imp; - } - target_os = "motor" => { - use moto_rt::time as imp; - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod sgx; - use sgx as imp; - } - target_os = "solid_asp3" => { - mod solid; - use solid as imp; - } - target_os = "uefi" => { - mod uefi; - use uefi as imp; - } - any( - target_os = "teeos", - target_family = "unix", - target_os = "wasi", - ) => { - mod unix; - use unix as imp; - } - target_os = "vexos" => { - mod vexos; - #[expect(unused)] - mod unsupported; - - mod imp { - pub use super::vexos::Instant; - pub use super::unsupported::{SystemTime, UNIX_EPOCH}; - } - } - target_os = "windows" => { - mod windows; - use windows as imp; - } - target_os = "xous" => { - mod xous; - use xous as imp; - } - _ => { - mod unsupported; - use unsupported as imp; - } -} - -pub use imp::{Instant, SystemTime, UNIX_EPOCH}; diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs new file mode 120000 index 0000000..1a43613 --- /dev/null +++ b/library/std/src/sys/time/mod.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/time/mod.rs \ No newline at end of file diff --git a/library/std/src/sys/time/unsupported.rs b/library/std/src/sys/time/unsupported.rs deleted file mode 100644 index 9bdd572..0000000 --- a/library/std/src/sys/time/unsupported.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::time::Duration; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); - -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); - -impl Instant { - pub fn now() -> Instant { - panic!("time not implemented on this platform") - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) - } -} - -impl SystemTime { - pub const MAX: SystemTime = SystemTime(Duration::MAX); - - pub const MIN: SystemTime = SystemTime(Duration::ZERO); - - pub fn now() -> SystemTime { - panic!("time not implemented on this platform") - } - - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) - } -} diff --git a/library/std/src/sys/time/unsupported.rs b/library/std/src/sys/time/unsupported.rs new file mode 120000 index 0000000..4a54ab1 --- /dev/null +++ b/library/std/src/sys/time/unsupported.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/time/unsupported.rs \ No newline at end of file diff --git a/library/std/src/time.rs b/library/std/src/time.rs deleted file mode 100644 index 1805d89..0000000 --- a/library/std/src/time.rs +++ /dev/null @@ -1,859 +0,0 @@ -//! Temporal quantification. -//! -//! # Examples -//! -//! There are multiple ways to create a new [`Duration`]: -//! -//! ``` -//! # use std::time::Duration; -//! let five_seconds = Duration::from_secs(5); -//! assert_eq!(five_seconds, Duration::from_millis(5_000)); -//! assert_eq!(five_seconds, Duration::from_micros(5_000_000)); -//! assert_eq!(five_seconds, Duration::from_nanos(5_000_000_000)); -//! -//! let ten_seconds = Duration::from_secs(10); -//! let seven_nanos = Duration::from_nanos(7); -//! let total = ten_seconds + seven_nanos; -//! assert_eq!(total, Duration::new(10, 7)); -//! ``` -//! -//! Using [`Instant`] to calculate how long a function took to run: -//! -//! ```ignore (incomplete) -//! let now = Instant::now(); -//! -//! // Calling a slow function, it may take a while -//! slow_function(); -//! -//! let elapsed_time = now.elapsed(); -//! println!("Running slow_function() took {} seconds.", elapsed_time.as_secs()); -//! ``` - -#![stable(feature = "time", since = "1.3.0")] - -#[stable(feature = "time", since = "1.3.0")] -pub use core::time::Duration; -#[stable(feature = "duration_checked_float", since = "1.66.0")] -pub use core::time::TryFromFloatSecsError; - -use crate::error::Error; -use crate::fmt; -use crate::ops::{Add, AddAssign, Sub, SubAssign}; -use crate::sys::{FromInner, IntoInner, time}; - -/// A measurement of a monotonically nondecreasing clock. -/// Opaque and useful only with [`Duration`]. -/// -/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously -/// measured instant when created, and are often useful for tasks such as measuring -/// benchmarks or timing how long an operation takes. -/// -/// Note, however, that instants are **not** guaranteed to be **steady**. In other -/// words, each tick of the underlying clock might not be the same length (e.g. -/// some seconds may be longer than others). An instant may jump forwards or -/// experience time dilation (slow down or speed up), but it will never go -/// backwards. -/// As part of this non-guarantee it is also not specified whether system suspends count as -/// elapsed time or not. The behavior varies across platforms and Rust versions. -/// -/// Instants are opaque types that can only be compared to one another. There is -/// no method to get "the number of seconds" from an instant. Instead, it only -/// allows measuring the duration between two instants (or comparing two -/// instants). -/// -/// The size of an `Instant` struct may vary depending on the target operating -/// system. -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, Instant}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = Instant::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// // it prints '2' -/// println!("{}", now.elapsed().as_secs()); -/// } -/// ``` -/// -/// [platform bugs]: Instant#monotonicity -/// -/// # OS-specific behaviors -/// -/// An `Instant` is a wrapper around system-specific types and it may behave -/// differently depending on the underlying operating system. For example, -/// the following snippet is fine on Linux but panics on macOS: -/// -/// ```no_run -/// use std::time::{Instant, Duration}; -/// -/// let now = Instant::now(); -/// let days_per_10_millennia = 365_2425; -/// let solar_seconds_per_day = 60 * 60 * 24; -/// let millennium_in_solar_seconds = 31_556_952_000; -/// assert_eq!(millennium_in_solar_seconds, days_per_10_millennia * solar_seconds_per_day / 10); -/// -/// let duration = Duration::new(millennium_in_solar_seconds, 0); -/// println!("{:?}", now + duration); -/// ``` -/// -/// For cross-platform code, you can comfortably use durations of up to around one hundred years. -/// -/// # Underlying System calls -/// -/// The following system calls are [currently] being used by `now()` to find out -/// the current time: -/// -/// | Platform | System call | -/// |-----------|----------------------------------------------------------------------| -/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | -/// | UNIX | [clock_gettime] with `CLOCK_MONOTONIC` | -/// | Darwin | [clock_gettime] with `CLOCK_UPTIME_RAW` | -/// | VXWorks | [clock_gettime] with `CLOCK_MONOTONIC` | -/// | SOLID | `get_tim` | -/// | WASI | [__wasi_clock_time_get] with `monotonic` | -/// | Windows | [QueryPerformanceCounter] | -/// -/// [currently]: crate::io#platform-specific-behavior -/// [QueryPerformanceCounter]: https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter -/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time -/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode -/// [__wasi_clock_time_get]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get -/// [clock_gettime]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html -/// -/// **Disclaimer:** These system calls might change over time. -/// -/// > Note: mathematical operations like [`add`] may panic if the underlying -/// > structure cannot represent the new point in time. -/// -/// [`add`]: Instant::add -/// -/// ## Monotonicity -/// -/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior -/// if available, which is the case for all [tier 1] platforms. -/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization -/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks -/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this -/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations -/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order. -/// -/// This workaround obscures programming errors where earlier and later instants are accidentally -/// swapped. For this reason future Rust versions may reintroduce panics. -/// -/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html -/// [`duration_since`]: Instant::duration_since -/// [`elapsed`]: Instant::elapsed -/// [`sub`]: Instant::sub -/// [`checked_duration_since`]: Instant::checked_duration_since -/// -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Instant")] -pub struct Instant(time::Instant); - -/// A measurement of the system clock, useful for talking to -/// external entities like the file system or other processes. -/// -/// Distinct from the [`Instant`] type, this time measurement **is not -/// monotonic**. This means that you can save a file to the file system, then -/// save another file to the file system, **and the second file has a -/// `SystemTime` measurement earlier than the first**. In other words, an -/// operation that happens after another operation in real time may have an -/// earlier `SystemTime`! -/// -/// Consequently, comparing two `SystemTime` instances to learn about the -/// duration between them returns a [`Result`] instead of an infallible [`Duration`] -/// to indicate that this sort of time drift may happen and needs to be handled. -/// -/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] -/// constant is provided in this module as an anchor in time to learn -/// information about a `SystemTime`. By calculating the duration from this -/// fixed point in time, a `SystemTime` can be converted to a human-readable time, -/// or perhaps some other string representation. -/// -/// The size of a `SystemTime` struct may vary depending on the target operating -/// system. -/// -/// A `SystemTime` does not count leap seconds. -/// `SystemTime::now()`'s behavior around a leap second -/// is the same as the operating system's wall clock. -/// The precise behavior near a leap second -/// (e.g. whether the clock appears to run slow or fast, or stop, or jump) -/// depends on platform and configuration, -/// so should not be relied on. -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, SystemTime}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = SystemTime::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// match now.elapsed() { -/// Ok(elapsed) => { -/// // it prints '2' -/// println!("{}", elapsed.as_secs()); -/// } -/// Err(e) => { -/// // the system clock went backwards! -/// println!("Great Scott! {e:?}"); -/// } -/// } -/// } -/// ``` -/// -/// # Platform-specific behavior -/// -/// The precision of `SystemTime` can depend on the underlying OS-specific time format. -/// For example, on Windows the time is represented in 100 nanosecond intervals whereas Linux -/// can represent nanosecond intervals. -/// -/// The following system calls are [currently] being used by `now()` to find out -/// the current time: -/// -/// | Platform | System call | -/// |-----------|----------------------------------------------------------------------| -/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | -/// | UNIX | [clock_gettime (Realtime Clock)] | -/// | Darwin | [clock_gettime (Realtime Clock)] | -/// | VXWorks | [clock_gettime (Realtime Clock)] | -/// | SOLID | `SOLID_RTC_ReadTime` | -/// | WASI | [__wasi_clock_time_get (Realtime Clock)] | -/// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | -/// -/// [currently]: crate::io#platform-specific-behavior -/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time -/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode -/// [clock_gettime (Realtime Clock)]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html -/// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get -/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime -/// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime -/// -/// **Disclaimer:** These system calls might change over time. -/// -/// > Note: mathematical operations like [`add`] may panic if the underlying -/// > structure cannot represent the new point in time. -/// -/// [`add`]: SystemTime::add -/// [`UNIX_EPOCH`]: SystemTime::UNIX_EPOCH -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTime(time::SystemTime); - -/// An error returned from the `duration_since` and `elapsed` methods on -/// `SystemTime`, used to learn how far in the opposite direction a system time -/// lies. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread::sleep; -/// use std::time::{Duration, SystemTime}; -/// -/// let sys_time = SystemTime::now(); -/// sleep(Duration::from_secs(1)); -/// let new_sys_time = SystemTime::now(); -/// match sys_time.duration_since(new_sys_time) { -/// Ok(_) => {} -/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), -/// } -/// ``` -#[derive(Clone, Debug)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTimeError(Duration); - -impl Instant { - /// Returns an instant corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::Instant; - /// - /// let now = Instant::now(); - /// ``` - #[must_use] - #[stable(feature = "time2", since = "1.8.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "instant_now")] - pub fn now() -> Instant { - Instant(time::Instant::now()) - } - - /// Returns the amount of time elapsed from another instant to this one, - /// or zero duration if that instant is later than this one. - /// - /// # Panics - /// - /// Previous Rust versions panicked when `earlier` was later than `self`. Currently this - /// method saturates. Future versions may reintroduce the panic in some circumstances. - /// See [Monotonicity]. - /// - /// [Monotonicity]: Instant#monotonicity - /// - /// # Examples - /// - /// ```no_run - /// use std::time::{Duration, Instant}; - /// use std::thread::sleep; - /// - /// let now = Instant::now(); - /// sleep(Duration::new(1, 0)); - /// let new_now = Instant::now(); - /// println!("{:?}", new_now.duration_since(now)); - /// println!("{:?}", now.duration_since(new_now)); // 0ns - /// ``` - #[must_use] - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: Instant) -> Duration { - self.checked_duration_since(earlier).unwrap_or_default() - } - - /// Returns the amount of time elapsed from another instant to this one, - /// or None if that instant is later than this one. - /// - /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s, - /// this method can return `None`. - /// - /// [monotonicity bugs]: Instant#monotonicity - /// - /// # Examples - /// - /// ```no_run - /// use std::time::{Duration, Instant}; - /// use std::thread::sleep; - /// - /// let now = Instant::now(); - /// sleep(Duration::new(1, 0)); - /// let new_now = Instant::now(); - /// println!("{:?}", new_now.checked_duration_since(now)); - /// println!("{:?}", now.checked_duration_since(new_now)); // None - /// ``` - #[must_use] - #[stable(feature = "checked_duration_since", since = "1.39.0")] - pub fn checked_duration_since(&self, earlier: Instant) -> Option { - self.0.checked_sub_instant(&earlier.0) - } - - /// Returns the amount of time elapsed from another instant to this one, - /// or zero duration if that instant is later than this one. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::{Duration, Instant}; - /// use std::thread::sleep; - /// - /// let now = Instant::now(); - /// sleep(Duration::new(1, 0)); - /// let new_now = Instant::now(); - /// println!("{:?}", new_now.saturating_duration_since(now)); - /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns - /// ``` - #[must_use] - #[stable(feature = "checked_duration_since", since = "1.39.0")] - pub fn saturating_duration_since(&self, earlier: Instant) -> Duration { - self.checked_duration_since(earlier).unwrap_or_default() - } - - /// Returns the amount of time elapsed since this instant. - /// - /// # Panics - /// - /// Previous Rust versions panicked when the current time was earlier than self. Currently this - /// method returns a Duration of zero in that case. Future versions may reintroduce the panic. - /// See [Monotonicity]. - /// - /// [Monotonicity]: Instant#monotonicity - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, Instant}; - /// - /// let instant = Instant::now(); - /// let three_secs = Duration::from_secs(3); - /// sleep(three_secs); - /// assert!(instant.elapsed() >= three_secs); - /// ``` - #[must_use] - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Duration { - Instant::now() - *self - } - - /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as - /// `Instant` (which means it's inside the bounds of the underlying data structure), `None` - /// otherwise. - #[stable(feature = "time_checked_add", since = "1.34.0")] - pub fn checked_add(&self, duration: Duration) -> Option { - self.0.checked_add_duration(&duration).map(Instant) - } - - /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as - /// `Instant` (which means it's inside the bounds of the underlying data structure), `None` - /// otherwise. - #[stable(feature = "time_checked_add", since = "1.34.0")] - pub fn checked_sub(&self, duration: Duration) -> Option { - self.0.checked_sub_duration(&duration).map(Instant) - } - - // Used by platform specific `sleep_until` implementations such as the one used on Linux. - #[cfg_attr( - not(target_os = "linux"), - allow(unused, reason = "not every platform has a specific `sleep_until`") - )] - pub(crate) fn into_inner(self) -> time::Instant { - self.0 - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for Instant { - type Output = Instant; - - /// # Panics - /// - /// This function may panic if the resulting point in time cannot be represented by the - /// underlying data structure. See [`Instant::checked_add`] for a version without panic. - fn add(self, other: Duration) -> Instant { - self.checked_add(other).expect("overflow when adding duration to instant") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Instant { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Instant; - - fn sub(self, other: Duration) -> Instant { - self.checked_sub(other).expect("overflow when subtracting duration from instant") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Instant { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Duration; - - /// Returns the amount of time elapsed from another instant to this one, - /// or zero duration if that instant is later than this one. - /// - /// # Panics - /// - /// Previous Rust versions panicked when `other` was later than `self`. Currently this - /// method saturates. Future versions may reintroduce the panic in some circumstances. - /// See [Monotonicity]. - /// - /// [Monotonicity]: Instant#monotonicity - fn sub(self, other: Instant) -> Duration { - self.duration_since(other) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl SystemTime { - /// An anchor in time which can be used to create new `SystemTime` instances or - /// learn about where in time a `SystemTime` lies. - // - // NOTE! this documentation is duplicated, here and in std::time::UNIX_EPOCH. - // The two copies are not quite identical, because of the difference in naming. - /// - /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with - /// respect to the system clock. Using `duration_since` on an existing - /// `SystemTime` instance can tell how far away from this point in time a - /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a - /// `SystemTime` instance to represent another fixed point in time. - /// - /// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns - /// the number of non-leap seconds since the start of 1970 UTC. - /// This is a POSIX `time_t` (as a `u64`), - /// and is the same time representation as used in many Internet protocols. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::SystemTime; - /// - /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { - /// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), - /// Err(_) => panic!("SystemTime before UNIX EPOCH!"), - /// } - /// ``` - #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] - pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; - - /// Represents the maximum value representable by [`SystemTime`] on this platform. - /// - /// This value differs a lot between platforms, but it is always the case - /// that any positive addition of a [`Duration`], whose value is greater - /// than or equal to the time precision of the operating system, to - /// [`SystemTime::MAX`] will fail. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(time_systemtime_limits)] - /// use std::time::{Duration, SystemTime}; - /// - /// // Adding zero will change nothing. - /// assert_eq!(SystemTime::MAX.checked_add(Duration::ZERO), Some(SystemTime::MAX)); - /// - /// // But adding just one second will already fail ... - /// // - /// // Keep in mind that this in fact may succeed, if the Duration is - /// // smaller than the time precision of the operating system, which - /// // happens to be 1ns on most operating systems, with Windows being the - /// // notable exception by using 100ns, hence why this example uses 1s. - /// assert_eq!(SystemTime::MAX.checked_add(Duration::new(1, 0)), None); - /// - /// // Utilize this for saturating arithmetic to improve error handling. - /// // In this case, we will use a certificate with a timestamp in the - /// // future as a practical example. - /// let configured_offset = Duration::from_secs(60 * 60 * 24); - /// let valid_after = - /// SystemTime::now() - /// .checked_add(configured_offset) - /// .unwrap_or(SystemTime::MAX); - /// ``` - #[unstable(feature = "time_systemtime_limits", issue = "149067")] - pub const MAX: SystemTime = SystemTime(time::SystemTime::MAX); - - /// Represents the minimum value representable by [`SystemTime`] on this platform. - /// - /// This value differs a lot between platforms, but it is always the case - /// that any positive subtraction of a [`Duration`] from, whose value is - /// greater than or equal to the time precision of the operating system, to - /// [`SystemTime::MIN`] will fail. - /// - /// Depending on the platform, this may be either less than or equal to - /// [`SystemTime::UNIX_EPOCH`], depending on whether the operating system - /// supports the representation of timestamps before the Unix epoch or not. - /// However, it is always guaranteed that a [`SystemTime::UNIX_EPOCH`] fits - /// between a [`SystemTime::MIN`] and [`SystemTime::MAX`]. - /// - /// # Examples - /// - /// ``` - /// #![feature(time_systemtime_limits)] - /// use std::time::{Duration, SystemTime}; - /// - /// // Subtracting zero will change nothing. - /// assert_eq!(SystemTime::MIN.checked_sub(Duration::ZERO), Some(SystemTime::MIN)); - /// - /// // But subtracting just one second will already fail. - /// // - /// // Keep in mind that this in fact may succeed, if the Duration is - /// // smaller than the time precision of the operating system, which - /// // happens to be 1ns on most operating systems, with Windows being the - /// // notable exception by using 100ns, hence why this example uses 1s. - /// assert_eq!(SystemTime::MIN.checked_sub(Duration::new(1, 0)), None); - /// - /// // Utilize this for saturating arithmetic to improve error handling. - /// // In this case, we will use a cache expiry as a practical example. - /// let configured_expiry = Duration::from_secs(60 * 3); - /// let expiry_threshold = - /// SystemTime::now() - /// .checked_sub(configured_expiry) - /// .unwrap_or(SystemTime::MIN); - /// ``` - #[unstable(feature = "time_systemtime_limits", issue = "149067")] - pub const MIN: SystemTime = SystemTime(time::SystemTime::MIN); - - /// Returns the system time corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// ``` - #[must_use] - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> SystemTime { - SystemTime(time::SystemTime::now()) - } - - /// Returns the amount of time elapsed from an earlier point in time. - /// - /// This function may fail because measurements taken earlier are not - /// guaranteed to always be before later measurements (due to anomalies such - /// as the system clock being adjusted either forwards or backwards). - /// [`Instant`] can be used to measure elapsed time without this risk of failure. - /// - /// If successful, [Ok]\([Duration]) is returned where the duration represents - /// the amount of time elapsed from the specified measurement to this one. - /// - /// Returns an [`Err`] if `earlier` is later than `self`, and the error - /// contains how far from `self` the time is. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// let new_sys_time = SystemTime::now(); - /// let difference = new_sys_time.duration_since(sys_time) - /// .expect("Clock may have gone backwards"); - /// println!("{difference:?}"); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) -> Result { - self.0.sub_time(&earlier.0).map_err(SystemTimeError) - } - - /// Returns the difference from this system time to the - /// current clock time. - /// - /// This function may fail as the underlying system clock is susceptible to - /// drift and updates (e.g., the system clock could go backwards), so this - /// function might not always succeed. If successful, [Ok]\([Duration]) is - /// returned where the duration represents the amount of time elapsed from - /// this time measurement to the current time. - /// - /// To measure elapsed time reliably, use [`Instant`] instead. - /// - /// Returns an [`Err`] if `self` is later than the current system time, and - /// the error contains how far from the current system time `self` is. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// let one_sec = Duration::from_secs(1); - /// sleep(one_sec); - /// assert!(sys_time.elapsed().unwrap() >= one_sec); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Result { - SystemTime::now().duration_since(*self) - } - - /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as - /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` - /// otherwise. - /// - /// In the case that the `duration` is smaller than the time precision of the operating - /// system, `Some(self)` will be returned. - #[stable(feature = "time_checked_add", since = "1.34.0")] - pub fn checked_add(&self, duration: Duration) -> Option { - self.0.checked_add_duration(&duration).map(SystemTime) - } - - /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as - /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` - /// otherwise. - /// - /// In the case that the `duration` is smaller than the time precision of the operating - /// system, `Some(self)` will be returned. - #[stable(feature = "time_checked_add", since = "1.34.0")] - pub fn checked_sub(&self, duration: Duration) -> Option { - self.0.checked_sub_duration(&duration).map(SystemTime) - } - - /// Saturating [`SystemTime`] addition, computing `self + duration`, - /// returning [`SystemTime::MAX`] if overflow occurred. - /// - /// In the case that the `duration` is smaller than the time precision of - /// the operating system, `self` will be returned. - #[unstable(feature = "time_saturating_systemtime", issue = "151199")] - pub fn saturating_add(&self, duration: Duration) -> SystemTime { - self.checked_add(duration).unwrap_or(SystemTime::MAX) - } - - /// Saturating [`SystemTime`] subtraction, computing `self - duration`, - /// returning [`SystemTime::MIN`] if overflow occurred. - /// - /// In the case that the `duration` is smaller than the time precision of - /// the operating system, `self` will be returned. - #[unstable(feature = "time_saturating_systemtime", issue = "151199")] - pub fn saturating_sub(&self, duration: Duration) -> SystemTime { - self.checked_sub(duration).unwrap_or(SystemTime::MIN) - } - - /// Saturating computation of time elapsed from an earlier point in time, - /// returning [`Duration::ZERO`] in the case that `earlier` is later or - /// equal to `self`. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(time_saturating_systemtime)] - /// use std::time::{Duration, SystemTime}; - /// - /// let now = SystemTime::now(); - /// let prev = now.saturating_sub(Duration::new(1, 0)); - /// - /// // now - prev should return non-zero. - /// assert_eq!(now.saturating_duration_since(prev), Duration::new(1, 0)); - /// assert!(now.duration_since(prev).is_ok()); - /// - /// // prev - now should return zero (and fail with the non-saturating). - /// assert_eq!(prev.saturating_duration_since(now), Duration::ZERO); - /// assert!(prev.duration_since(now).is_err()); - /// - /// // now - now should return zero (and work with the non-saturating). - /// assert_eq!(now.saturating_duration_since(now), Duration::ZERO); - /// assert!(now.duration_since(now).is_ok()); - /// ``` - #[unstable(feature = "time_saturating_systemtime", issue = "151199")] - pub fn saturating_duration_since(&self, earlier: SystemTime) -> Duration { - self.duration_since(earlier).unwrap_or(Duration::ZERO) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for SystemTime { - type Output = SystemTime; - - /// # Panics - /// - /// This function may panic if the resulting point in time cannot be represented by the - /// underlying data structure. See [`SystemTime::checked_add`] for a version without panic. - fn add(self, dur: Duration) -> SystemTime { - self.checked_add(dur).expect("overflow when adding duration to instant") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for SystemTime { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for SystemTime { - type Output = SystemTime; - - fn sub(self, dur: Duration) -> SystemTime { - self.checked_sub(dur).expect("overflow when subtracting duration from instant") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for SystemTime { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// An anchor in time which can be used to create new `SystemTime` instances or -/// learn about where in time a `SystemTime` lies. -// -// NOTE! this documentation is duplicated, here and in SystemTime::UNIX_EPOCH. -// The two copies are not quite identical, because of the difference in naming. -/// -/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with -/// respect to the system clock. Using `duration_since` on an existing -/// [`SystemTime`] instance can tell how far away from this point in time a -/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a -/// [`SystemTime`] instance to represent another fixed point in time. -/// -/// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns -/// the number of non-leap seconds since the start of 1970 UTC. -/// This is a POSIX `time_t` (as a `u64`), -/// and is the same time representation as used in many Internet protocols. -/// -/// # Examples -/// -/// ```no_run -/// use std::time::{SystemTime, UNIX_EPOCH}; -/// -/// match SystemTime::now().duration_since(UNIX_EPOCH) { -/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), -/// Err(_) => panic!("SystemTime before UNIX EPOCH!"), -/// } -/// ``` -#[stable(feature = "time2", since = "1.8.0")] -pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); - -impl SystemTimeError { - /// Returns the positive duration which represents how far forward the - /// second system time was from the first. - /// - /// A `SystemTimeError` is returned from the [`SystemTime::duration_since`] - /// and [`SystemTime::elapsed`] methods whenever the second system time - /// represents a point later in time than the `self` of the method call. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// sleep(Duration::from_secs(1)); - /// let new_sys_time = SystemTime::now(); - /// match sys_time.duration_since(new_sys_time) { - /// Ok(_) => {} - /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), - /// } - /// ``` - #[must_use] - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration(&self) -> Duration { - self.0 - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Error for SystemTimeError {} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Display for SystemTimeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "second time provided was later than self") - } -} - -impl FromInner for SystemTime { - fn from_inner(time: time::SystemTime) -> SystemTime { - SystemTime(time) - } -} - -impl IntoInner for SystemTime { - fn into_inner(self) -> time::SystemTime { - self.0 - } -} diff --git a/library/std/src/time.rs b/library/std/src/time.rs new file mode 120000 index 0000000..391a9ba --- /dev/null +++ b/library/std/src/time.rs @@ -0,0 +1 @@ +/home/julien/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/time.rs \ No newline at end of file