Merge branch 'master' of https://github.com/rust-lang/rust
Conflicts: src/libcoretest/lib.rs
This commit is contained in:
commit
655effedf2
1501 changed files with 41721 additions and 34051 deletions
765
src/Cargo.lock
generated
Normal file
765
src/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,765 @@
|
|||
[root]
|
||||
name = "unwind"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc_jemalloc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"core 0.0.0",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc_system"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arena"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.38 (git+https://github.com/alexcrichton/gcc-rs)",
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build_helper"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "cargotest"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collections"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"core 0.0.0",
|
||||
"rustc_unicode 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compiletest"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serialize 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error_index_generator"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fmt_macros"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.38"
|
||||
source = "git+https://github.com/alexcrichton/gcc-rs#be620ac6d3ddb498cd0c700d5312c6a4c3c19597"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "graphviz"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "linkchecker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"url 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic_abort"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic_unwind"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"core 0.0.0",
|
||||
"libc 0.0.0",
|
||||
"unwind 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc_macro"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"syntax 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc_macro_plugin"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"proc_macro_tokens 0.0.0",
|
||||
"rustc_plugin 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc_macro_tokens"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustbook"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "rustc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"flate 0.0.0",
|
||||
"fmt_macros 0.0.0",
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_bitflags 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_llvm 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-main"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_driver 0.0.0",
|
||||
"rustdoc 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_back"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_bitflags"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_borrowck"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_const_eval"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_const_math"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_data_structures"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_driver"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"flate 0.0.0",
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"proc_macro_plugin 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_borrowck 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_incremental 0.0.0",
|
||||
"rustc_lint 0.0.0",
|
||||
"rustc_llvm 0.0.0",
|
||||
"rustc_metadata 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
"rustc_passes 0.0.0",
|
||||
"rustc_plugin 0.0.0",
|
||||
"rustc_privacy 0.0.0",
|
||||
"rustc_resolve 0.0.0",
|
||||
"rustc_save_analysis 0.0.0",
|
||||
"rustc_trans 0.0.0",
|
||||
"rustc_typeck 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_ext 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_errors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_incremental"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_lint"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_llvm"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_bitflags 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_metadata"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"flate 0.0.0",
|
||||
"log 0.0.0",
|
||||
"proc_macro 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_llvm 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_ext 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_mir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_bitflags 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_passes"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_platform_intrinsics"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_plugin"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_bitflags 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_metadata 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_privacy"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_resolve"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_save_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_trans"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"flate 0.0.0",
|
||||
"graphviz 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_incremental 0.0.0",
|
||||
"rustc_llvm 0.0.0",
|
||||
"rustc_platform_intrinsics 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_typeck"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"fmt_macros 0.0.0",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_platform_intrinsics 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_unicode"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arena 0.0.0",
|
||||
"build_helper 0.1.0",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.0.0",
|
||||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_driver 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_lint 0.0.0",
|
||||
"rustc_metadata 0.0.0",
|
||||
"rustc_resolve 0.0.0",
|
||||
"rustc_trans 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serialize"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "std"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"alloc_jemalloc 0.0.0",
|
||||
"alloc_system 0.0.0",
|
||||
"build_helper 0.1.0",
|
||||
"collections 0.0.0",
|
||||
"compiler_builtins 0.0.0",
|
||||
"core 0.0.0",
|
||||
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.0.0",
|
||||
"panic_abort 0.0.0",
|
||||
"panic_unwind 0.0.0",
|
||||
"rand 0.0.0",
|
||||
"rustc_unicode 0.0.0",
|
||||
"unwind 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "std_shim"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"core 0.0.0",
|
||||
"std 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntax"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.0.0",
|
||||
"rustc_bitflags 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntax_ext"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"fmt_macros 0.0.0",
|
||||
"log 0.0.0",
|
||||
"proc_macro 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntax_pos"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"serialize 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "test"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"getopts 0.0.0",
|
||||
"term 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test_shim"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"test 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tidy"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
|
||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||
"checksum gcc 0.3.38 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
|
||||
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
||||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
|
||||
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
|
||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||
"checksum matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc3ad8109fa4b522f9b0cd81440422781f564aaf8c195de6b9d6642177ad0dd"
|
||||
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
|
||||
"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3"
|
||||
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
||||
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
|
||||
"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
|
||||
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
|
||||
"checksum url 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ba5a45db1d2e0effb7a1c00cc73ffc63a973da8c7d1fcd5b46f24285ade6c54"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
13
src/Cargo.toml
Normal file
13
src/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"bootstrap",
|
||||
"rustc",
|
||||
"rustc/std_shim",
|
||||
"rustc/test_shim",
|
||||
"tools/cargotest",
|
||||
"tools/compiletest",
|
||||
"tools/error_index_generator",
|
||||
"tools/linkchecker",
|
||||
"tools/rustbook",
|
||||
"tools/tidy",
|
||||
]
|
||||
180
src/bootstrap/Cargo.lock
generated
180
src/bootstrap/Cargo.lock
generated
|
|
@ -1,180 +0,0 @@
|
|||
[root]
|
||||
name = "bootstrap"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)",
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "build_helper"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.31"
|
||||
source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7"
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "md5"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
|
||||
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
|
||||
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
|
||||
"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
|
||||
"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07"
|
||||
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0"
|
||||
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
|
||||
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
|
||||
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
|
||||
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
|
||||
"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
|
@ -27,9 +27,10 @@ num_cpus = "0.2"
|
|||
toml = "0.1"
|
||||
getopts = "0.2"
|
||||
rustc-serialize = "0.3"
|
||||
winapi = "0.2"
|
||||
kernel32-sys = "0.2"
|
||||
gcc = { git = "https://github.com/alexcrichton/gcc-rs" }
|
||||
libc = "0.2"
|
||||
md5 = "0.1"
|
||||
regex = "0.1.73"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = "0.2"
|
||||
kernel32-sys = "0.2"
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ fn main() {
|
|||
let args = env::args_os().skip(1).collect::<Vec<_>>();
|
||||
// Detect whether or not we're a build script depending on whether --target
|
||||
// is passed (a bit janky...)
|
||||
let target = args.windows(2).find(|w| &*w[0] == "--target")
|
||||
.and_then(|w| w[1].to_str());
|
||||
let target = args.windows(2)
|
||||
.find(|w| &*w[0] == "--target")
|
||||
.and_then(|w| w[1].to_str());
|
||||
let version = args.iter().find(|w| &**w == "-vV");
|
||||
|
||||
// Build scripts always use the snapshot compiler which is guaranteed to be
|
||||
|
|
@ -55,23 +56,24 @@ fn main() {
|
|||
} else {
|
||||
("RUSTC_REAL", "RUSTC_LIBDIR")
|
||||
};
|
||||
let stage = env::var("RUSTC_STAGE").unwrap();
|
||||
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
|
||||
|
||||
let rustc = env::var_os(rustc).unwrap();
|
||||
let libdir = env::var_os(libdir).unwrap();
|
||||
let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
|
||||
let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
|
||||
let mut dylib_path = bootstrap::util::dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(libdir));
|
||||
|
||||
let mut cmd = Command::new(rustc);
|
||||
cmd.args(&args)
|
||||
.arg("--cfg").arg(format!("stage{}", stage))
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
.arg("--cfg")
|
||||
.arg(format!("stage{}", stage))
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
if let Some(target) = target {
|
||||
// The stage0 compiler has a special sysroot distinct from what we
|
||||
// actually downloaded, so we just always pass the `--sysroot` option.
|
||||
cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").unwrap());
|
||||
cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"));
|
||||
|
||||
// When we build Rust dylibs they're all intended for intermediate
|
||||
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
|
||||
|
|
@ -101,11 +103,9 @@ fn main() {
|
|||
// This... is a bit of a hack how we detect this. Ideally this
|
||||
// information should be encoded in the crate I guess? Would likely
|
||||
// require an RFC amendment to RFC 1513, however.
|
||||
let is_panic_abort = args.windows(2).any(|a| {
|
||||
&*a[0] == "--crate-name" && &*a[1] == "panic_abort"
|
||||
});
|
||||
// FIXME(stage0): remove this `stage != "0"` condition
|
||||
if is_panic_abort && stage != "0" {
|
||||
let is_panic_abort = args.windows(2)
|
||||
.any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort");
|
||||
if is_panic_abort {
|
||||
cmd.arg("-C").arg("panic=abort");
|
||||
}
|
||||
|
||||
|
|
@ -113,9 +113,11 @@ fn main() {
|
|||
// code.
|
||||
if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
|
||||
cmd.arg("-g");
|
||||
} else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) {
|
||||
cmd.arg("-Cdebuginfo=1");
|
||||
}
|
||||
let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") {
|
||||
Ok(s) => if s == "true" {"y"} else {"n"},
|
||||
Ok(s) => if s == "true" { "y" } else { "n" },
|
||||
Err(..) => "n",
|
||||
};
|
||||
cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
|
||||
|
|
|
|||
|
|
@ -20,21 +20,23 @@ use std::path::PathBuf;
|
|||
|
||||
fn main() {
|
||||
let args = env::args_os().skip(1).collect::<Vec<_>>();
|
||||
let rustdoc = env::var_os("RUSTDOC_REAL").unwrap();
|
||||
let libdir = env::var_os("RUSTC_LIBDIR").unwrap();
|
||||
let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
|
||||
let libdir = env::var_os("RUSTC_LIBDIR").expect("RUSTC_LIBDIR was not set");
|
||||
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
|
||||
|
||||
let mut dylib_path = bootstrap::util::dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(libdir));
|
||||
|
||||
let mut cmd = Command::new(rustdoc);
|
||||
cmd.args(&args)
|
||||
.arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()))
|
||||
.arg("--cfg").arg("dox")
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
.arg("--cfg")
|
||||
.arg(format!("stage{}", stage))
|
||||
.arg("--cfg")
|
||||
.arg("dox")
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
std::process::exit(match cmd.status() {
|
||||
Ok(s) => s.code().unwrap_or(1),
|
||||
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ def stage0_data(rust_root):
|
|||
def format_build_time(duration):
|
||||
return str(datetime.timedelta(seconds=int(duration)))
|
||||
|
||||
class RustBuild:
|
||||
|
||||
class RustBuild(object):
|
||||
def download_stage0(self):
|
||||
cache_dst = os.path.join(self.build_dir, "cache")
|
||||
rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date())
|
||||
|
|
@ -142,7 +143,7 @@ class RustBuild:
|
|||
os.makedirs(cargo_cache)
|
||||
|
||||
if self.rustc().startswith(self.bin_root()) and \
|
||||
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
|
||||
(not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
|
||||
if os.path.exists(self.bin_root()):
|
||||
shutil.rmtree(self.bin_root())
|
||||
channel = self.stage0_rustc_channel()
|
||||
|
|
@ -165,7 +166,7 @@ class RustBuild:
|
|||
f.write(self.stage0_rustc_date())
|
||||
|
||||
if self.cargo().startswith(self.bin_root()) and \
|
||||
(not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
|
||||
(not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
|
||||
channel = self.stage0_cargo_channel()
|
||||
filename = "cargo-{}-{}.tar.gz".format(channel, self.build)
|
||||
url = "https://static.rust-lang.org/cargo-dist/" + self.stage0_cargo_date()
|
||||
|
|
@ -238,8 +239,8 @@ class RustBuild:
|
|||
|
||||
def get_string(self, line):
|
||||
start = line.find('"')
|
||||
end = start + 1 + line[start+1:].find('"')
|
||||
return line[start+1:end]
|
||||
end = start + 1 + line[start + 1:].find('"')
|
||||
return line[start + 1:end]
|
||||
|
||||
def exe_suffix(self):
|
||||
if sys.platform == 'win32':
|
||||
|
|
@ -269,6 +270,7 @@ class RustBuild:
|
|||
sys.exit(ret)
|
||||
|
||||
def build_triple(self):
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
config = self.get_toml('build')
|
||||
if config:
|
||||
return config
|
||||
|
|
@ -276,8 +278,8 @@ class RustBuild:
|
|||
if config:
|
||||
return config
|
||||
try:
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip()
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip()
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding)
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding)
|
||||
except (subprocess.CalledProcessError, WindowsError):
|
||||
if sys.platform == 'win32':
|
||||
return 'x86_64-pc-windows-msvc'
|
||||
|
|
@ -289,7 +291,8 @@ class RustBuild:
|
|||
# Darwin's `uname -s` lies and always returns i386. We have to use
|
||||
# sysctl instead.
|
||||
if ostype == 'Darwin' and cputype == 'i686':
|
||||
sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64'])
|
||||
args = ['sysctl', 'hw.optional.x86_64']
|
||||
sysctl = subprocess.check_output(args).decode(default_encoding)
|
||||
if ': 1' in sysctl:
|
||||
cputype = 'x86_64'
|
||||
|
||||
|
|
|
|||
|
|
@ -13,19 +13,44 @@
|
|||
//! This file implements the various regression test suites that we execute on
|
||||
//! our CI.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::fs;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::output;
|
||||
use rustc_serialize::json;
|
||||
|
||||
use {Build, Compiler, Mode};
|
||||
use util::{self, dylib_path, dylib_path_var};
|
||||
|
||||
const ADB_TEST_DIR: &'static str = "/data/tmp";
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Output {
|
||||
packages: Vec<Package>,
|
||||
resolve: Resolve,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Package {
|
||||
id: String,
|
||||
name: String,
|
||||
source: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Resolve {
|
||||
nodes: Vec<ResolveNode>,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct ResolveNode {
|
||||
id: String,
|
||||
dependencies: Vec<String>,
|
||||
}
|
||||
|
||||
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
|
||||
///
|
||||
/// This tool in `src/tools` will verify the validity of all our links in the
|
||||
|
|
@ -108,6 +133,10 @@ pub fn compiletest(build: &Build,
|
|||
cmd.arg("--host").arg(compiler.host);
|
||||
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
|
||||
|
||||
if let Some(nodejs) = build.config.nodejs.as_ref() {
|
||||
cmd.arg("--nodejs").arg(nodejs);
|
||||
}
|
||||
|
||||
let mut flags = vec!["-Crpath".to_string()];
|
||||
if build.config.rust_optimize_tests {
|
||||
flags.push("-O".to_string());
|
||||
|
|
@ -185,7 +214,7 @@ pub fn compiletest(build: &Build,
|
|||
}
|
||||
}
|
||||
}
|
||||
build.add_bootstrap_key(compiler, &mut cmd);
|
||||
build.add_bootstrap_key(&mut cmd);
|
||||
|
||||
cmd.arg("--adb-path").arg("adb");
|
||||
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
|
||||
|
|
@ -259,56 +288,74 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
|
|||
/// It essentially is the driver for running `cargo test`.
|
||||
///
|
||||
/// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
|
||||
/// arguments, and those arguments are discovered from `Cargo.lock`.
|
||||
/// arguments, and those arguments are discovered from `cargo metadata`.
|
||||
pub fn krate(build: &Build,
|
||||
compiler: &Compiler,
|
||||
target: &str,
|
||||
mode: Mode) {
|
||||
let (name, path, features) = match mode {
|
||||
Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features()),
|
||||
Mode::Libtest => ("libtest", "src/rustc/test_shim", String::new()),
|
||||
Mode::Librustc => ("librustc", "src/rustc", build.rustc_features()),
|
||||
let (name, path, features, root) = match mode {
|
||||
Mode::Libstd => {
|
||||
("libstd", "src/rustc/std_shim", build.std_features(), "std_shim")
|
||||
}
|
||||
Mode::Libtest => {
|
||||
("libtest", "src/rustc/test_shim", String::new(), "test_shim")
|
||||
}
|
||||
Mode::Librustc => {
|
||||
("librustc", "src/rustc", build.rustc_features(), "rustc-main")
|
||||
}
|
||||
_ => panic!("can only test libraries"),
|
||||
};
|
||||
println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
|
||||
compiler.host, target);
|
||||
|
||||
// Run `cargo metadata` to figure out what crates we're testing.
|
||||
//
|
||||
// Down below we're going to call `cargo test`, but to test the right set
|
||||
// of packages we're going to have to know what `-p` arguments to pass it
|
||||
// to know what crates to test. Here we run `cargo metadata` to learn about
|
||||
// the dependency graph and what `-p` arguments there are.
|
||||
let mut cargo = Command::new(&build.cargo);
|
||||
cargo.arg("metadata")
|
||||
.arg("--manifest-path").arg(build.src.join(path).join("Cargo.toml"));
|
||||
let output = output(&mut cargo);
|
||||
let output: Output = json::decode(&output).unwrap();
|
||||
let id2pkg = output.packages.iter()
|
||||
.map(|pkg| (&pkg.id, pkg))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let id2deps = output.resolve.nodes.iter()
|
||||
.map(|node| (&node.id, &node.dependencies))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// Build up the base `cargo test` command.
|
||||
//
|
||||
// Pass in some standard flags then iterate over the graph we've discovered
|
||||
// in `cargo metadata` with the maps above and figure out what `-p`
|
||||
// arguments need to get passed.
|
||||
let mut cargo = build.cargo(compiler, mode, target, "test");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join(path).join("Cargo.toml"))
|
||||
.arg("--features").arg(features);
|
||||
|
||||
// Generate a list of `-p` arguments to pass to the `cargo test` invocation
|
||||
// by crawling the corresponding Cargo.lock file.
|
||||
let lockfile = build.src.join(path).join("Cargo.lock");
|
||||
let mut contents = String::new();
|
||||
t!(t!(File::open(&lockfile)).read_to_string(&mut contents));
|
||||
let mut lines = contents.lines();
|
||||
while let Some(line) = lines.next() {
|
||||
let prefix = "name = \"";
|
||||
if !line.starts_with(prefix) {
|
||||
let mut visited = HashSet::new();
|
||||
let root_pkg = output.packages.iter().find(|p| p.name == root).unwrap();
|
||||
let mut next = vec![&root_pkg.id];
|
||||
while let Some(id) = next.pop() {
|
||||
// Skip any packages with sources listed, as these come from crates.io
|
||||
// and we shouldn't be testing them.
|
||||
if id2pkg[id].source.is_some() {
|
||||
continue
|
||||
}
|
||||
lines.next(); // skip `version = ...`
|
||||
|
||||
// skip crates.io or otherwise non-path crates
|
||||
if let Some(line) = lines.next() {
|
||||
if line.starts_with("source") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let crate_name = &line[prefix.len()..line.len() - 1];
|
||||
|
||||
// Right now jemalloc is our only target-specific crate in the sense
|
||||
// that it's not present on all platforms. Custom skip it here for now,
|
||||
// but if we add more this probably wants to get more generalized.
|
||||
if crate_name.contains("jemalloc") {
|
||||
continue
|
||||
if !id.contains("jemalloc") {
|
||||
cargo.arg("-p").arg(&id2pkg[id].name);
|
||||
}
|
||||
for dep in id2deps[id] {
|
||||
if visited.insert(dep) {
|
||||
next.push(dep);
|
||||
}
|
||||
}
|
||||
|
||||
cargo.arg("-p").arg(crate_name);
|
||||
}
|
||||
|
||||
// The tests are going to run with the *target* libraries, so we need to
|
||||
|
|
@ -323,6 +370,9 @@ pub fn krate(build: &Build,
|
|||
if target.contains("android") {
|
||||
build.run(cargo.arg("--no-run"));
|
||||
krate_android(build, compiler, target, mode);
|
||||
} else if target.contains("emscripten") {
|
||||
build.run(cargo.arg("--no-run"));
|
||||
krate_emscripten(build, compiler, target, mode);
|
||||
} else {
|
||||
cargo.args(&build.flags.args);
|
||||
build.run(&mut cargo);
|
||||
|
|
@ -371,6 +421,35 @@ fn krate_android(build: &Build,
|
|||
}
|
||||
}
|
||||
|
||||
fn krate_emscripten(build: &Build,
|
||||
compiler: &Compiler,
|
||||
target: &str,
|
||||
mode: Mode) {
|
||||
let mut tests = Vec::new();
|
||||
let out_dir = build.cargo_out(compiler, mode, target);
|
||||
find_tests(&out_dir, target, &mut tests);
|
||||
find_tests(&out_dir.join("deps"), target, &mut tests);
|
||||
|
||||
for test in tests {
|
||||
let test_file_name = test.to_string_lossy().into_owned();
|
||||
println!("running {}", test_file_name);
|
||||
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
|
||||
let status = Command::new(nodejs)
|
||||
.arg(&test_file_name)
|
||||
.stderr(::std::process::Stdio::inherit())
|
||||
.status();
|
||||
match status {
|
||||
Ok(status) => {
|
||||
if !status.success() {
|
||||
panic!("some tests failed");
|
||||
}
|
||||
}
|
||||
Err(e) => panic!(format!("failed to execute command: {}", e)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn find_tests(dir: &Path,
|
||||
target: &str,
|
||||
dst: &mut Vec<PathBuf>) {
|
||||
|
|
@ -381,7 +460,8 @@ fn find_tests(dir: &Path,
|
|||
}
|
||||
let filename = e.file_name().into_string().unwrap();
|
||||
if (target.contains("windows") && filename.ends_with(".exe")) ||
|
||||
(!target.contains("windows") && !filename.contains(".")) {
|
||||
(!target.contains("windows") && !filename.contains(".")) ||
|
||||
(target.contains("emscripten") && filename.contains(".js")){
|
||||
dst.push(e.path());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use std::process::Command;
|
|||
use build_helper::output;
|
||||
use filetime::FileTime;
|
||||
|
||||
use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
|
||||
use util::{exe, libdir, mtime, is_dylib, copy};
|
||||
use {Build, Compiler, Mode};
|
||||
|
||||
/// Build the standard library.
|
||||
|
|
@ -40,20 +40,6 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
let libdir = build.sysroot_libdir(compiler, target);
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
// FIXME(stage0) remove this `if` after the next snapshot
|
||||
// The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
|
||||
// never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
|
||||
// `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
|
||||
// an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
|
||||
// it to the final binary because now `libcore.rlib` also contains the symbols that
|
||||
// `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
|
||||
// symbols are used instead of `libcompiler-rt.a`'s.
|
||||
if compiler.stage == 0 {
|
||||
let rtlib = &staticlib("compiler-rt", target);
|
||||
let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
|
||||
.join(target).join("lib").join(rtlib);
|
||||
copy(&src, &libdir.join(rtlib));
|
||||
}
|
||||
|
||||
// Some platforms have startup objects that may be required to produce the
|
||||
// libstd dynamic library, for example.
|
||||
|
|
@ -104,16 +90,16 @@ pub fn std_link(build: &Build,
|
|||
add_to_sysroot(&out_dir, &libdir);
|
||||
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
copy_musl_third_party_objects(build, &libdir);
|
||||
copy_musl_third_party_objects(build, target, &libdir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the crt(1,i,n).o startup objects
|
||||
///
|
||||
/// Only required for musl targets that statically link to libc
|
||||
fn copy_musl_third_party_objects(build: &Build, into: &Path) {
|
||||
fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) {
|
||||
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
|
||||
copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj));
|
||||
copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +119,7 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
|
|||
for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
|
||||
let file = t!(file);
|
||||
let mut cmd = Command::new(&compiler_path);
|
||||
build.add_bootstrap_key(&compiler, &mut cmd);
|
||||
build.add_bootstrap_key(&mut cmd);
|
||||
build.run(cmd.arg("--target").arg(target)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
|
|
@ -199,7 +185,6 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
cargo.env("CFG_RELEASE", &build.release)
|
||||
.env("CFG_RELEASE_CHANNEL", &build.config.channel)
|
||||
.env("CFG_VERSION", &build.version)
|
||||
.env("CFG_BOOTSTRAP_KEY", &build.bootstrap_key)
|
||||
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new()))
|
||||
.env("CFG_LIBDIR_RELATIVE", "lib");
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ pub struct Config {
|
|||
pub rust_codegen_units: u32,
|
||||
pub rust_debug_assertions: bool,
|
||||
pub rust_debuginfo: bool,
|
||||
pub rust_debuginfo_lines: bool,
|
||||
pub rust_rpath: bool,
|
||||
pub rustc_default_linker: Option<String>,
|
||||
pub rustc_default_ar: Option<String>,
|
||||
|
|
@ -79,6 +80,9 @@ pub struct Config {
|
|||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub prefix: Option<String>,
|
||||
pub docdir: Option<String>,
|
||||
pub libdir: Option<String>,
|
||||
pub mandir: Option<String>,
|
||||
pub codegen_tests: bool,
|
||||
pub nodejs: Option<PathBuf>,
|
||||
}
|
||||
|
|
@ -117,6 +121,7 @@ struct Build {
|
|||
rustc: Option<String>,
|
||||
compiler_docs: Option<bool>,
|
||||
docs: Option<bool>,
|
||||
submodules: Option<bool>,
|
||||
}
|
||||
|
||||
/// TOML representation of how the LLVM build is configured.
|
||||
|
|
@ -137,6 +142,7 @@ struct Rust {
|
|||
codegen_units: Option<u32>,
|
||||
debug_assertions: Option<bool>,
|
||||
debuginfo: Option<bool>,
|
||||
debuginfo_lines: Option<bool>,
|
||||
debug_jemalloc: Option<bool>,
|
||||
use_jemalloc: Option<bool>,
|
||||
backtrace: Option<bool>,
|
||||
|
|
@ -158,6 +164,7 @@ struct TomlTarget {
|
|||
cc: Option<String>,
|
||||
cxx: Option<String>,
|
||||
android_ndk: Option<String>,
|
||||
musl_root: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
|
@ -221,6 +228,7 @@ impl Config {
|
|||
config.cargo = build.cargo.map(PathBuf::from);
|
||||
set(&mut config.compiler_docs, build.compiler_docs);
|
||||
set(&mut config.docs, build.docs);
|
||||
set(&mut config.submodules, build.submodules);
|
||||
|
||||
if let Some(ref llvm) = toml.llvm {
|
||||
set(&mut config.ccache, llvm.ccache);
|
||||
|
|
@ -233,6 +241,7 @@ impl Config {
|
|||
if let Some(ref rust) = toml.rust {
|
||||
set(&mut config.rust_debug_assertions, rust.debug_assertions);
|
||||
set(&mut config.rust_debuginfo, rust.debuginfo);
|
||||
set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines);
|
||||
set(&mut config.rust_optimize, rust.optimize);
|
||||
set(&mut config.rust_optimize_tests, rust.optimize_tests);
|
||||
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
|
||||
|
|
@ -268,6 +277,7 @@ impl Config {
|
|||
}
|
||||
target.cxx = cfg.cxx.clone().map(PathBuf::from);
|
||||
target.cc = cfg.cc.clone().map(PathBuf::from);
|
||||
target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
|
||||
|
||||
config.target_config.insert(triple.clone(), target);
|
||||
}
|
||||
|
|
@ -322,6 +332,7 @@ impl Config {
|
|||
("OPTIMIZE", self.rust_optimize),
|
||||
("DEBUG_ASSERTIONS", self.rust_debug_assertions),
|
||||
("DEBUGINFO", self.rust_debuginfo),
|
||||
("DEBUGINFO_LINES", self.rust_debuginfo_lines),
|
||||
("JEMALLOC", self.use_jemalloc),
|
||||
("DEBUG_JEMALLOC", self.debug_jemalloc),
|
||||
("RPATH", self.rust_rpath),
|
||||
|
|
@ -345,6 +356,36 @@ impl Config {
|
|||
"CFG_MUSL_ROOT" if value.len() > 0 => {
|
||||
self.musl_root = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_MUSL_ROOT_X86_64" if value.len() > 0 => {
|
||||
let target = "x86_64-unknown-linux-musl".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.musl_root = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_MUSL_ROOT_I686" if value.len() > 0 => {
|
||||
let target = "i686-unknown-linux-musl".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.musl_root = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_MUSL_ROOT_ARM" if value.len() > 0 => {
|
||||
let target = "arm-unknown-linux-musleabi".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.musl_root = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_MUSL_ROOT_ARMHF" if value.len() > 0 => {
|
||||
let target = "arm-unknown-linux-musleabihf".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.musl_root = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_MUSL_ROOT_ARMV7" if value.len() > 0 => {
|
||||
let target = "armv7-unknown-linux-musleabihf".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.musl_root = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_DEFAULT_AR" if value.len() > 0 => {
|
||||
self.rustc_default_ar = Some(value.to_string());
|
||||
}
|
||||
|
|
@ -357,6 +398,15 @@ impl Config {
|
|||
"CFG_PREFIX" => {
|
||||
self.prefix = Some(value.to_string());
|
||||
}
|
||||
"CFG_DOCDIR" => {
|
||||
self.docdir = Some(value.to_string());
|
||||
}
|
||||
"CFG_LIBDIR" => {
|
||||
self.libdir = Some(value.to_string());
|
||||
}
|
||||
"CFG_MANDIR" => {
|
||||
self.mandir = Some(value.to_string());
|
||||
}
|
||||
"CFG_LLVM_ROOT" if value.len() > 0 => {
|
||||
let target = self.target_config.entry(self.build.clone())
|
||||
.or_insert(Target::default());
|
||||
|
|
@ -396,9 +446,6 @@ impl Config {
|
|||
self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
|
||||
self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
|
||||
}
|
||||
"CFG_NODEJS" if value.len() > 0 => {
|
||||
self.nodejs = Some(PathBuf::from(value));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@
|
|||
# library and facade crates.
|
||||
#compiler-docs = false
|
||||
|
||||
# Indicate whether submodules are managed and updated automatically.
|
||||
#submodules = true
|
||||
|
||||
# =============================================================================
|
||||
# Options for compiling Rust code itself
|
||||
# =============================================================================
|
||||
|
|
@ -96,6 +99,9 @@
|
|||
# Whether or not debuginfo is emitted
|
||||
#debuginfo = false
|
||||
|
||||
# Whether or not line number debug information is emitted
|
||||
#debuginfo-lines = false
|
||||
|
||||
# Whether or not jemalloc is built and enabled
|
||||
#use-jemalloc = true
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@ use std::process::Command;
|
|||
|
||||
use {Build, Compiler};
|
||||
use util::{cp_r, libdir, is_dylib, cp_filtered, copy};
|
||||
use regex::{RegexSet, quote};
|
||||
|
||||
fn package_vers(build: &Build) -> &str {
|
||||
pub fn package_vers(build: &Build) -> &str {
|
||||
match &build.config.channel[..] {
|
||||
"stable" => &build.release,
|
||||
"beta" => "beta",
|
||||
|
|
@ -40,7 +39,7 @@ fn distdir(build: &Build) -> PathBuf {
|
|||
build.out.join("dist")
|
||||
}
|
||||
|
||||
fn tmpdir(build: &Build) -> PathBuf {
|
||||
pub fn tmpdir(build: &Build) -> PathBuf {
|
||||
build.out.join("tmp/dist")
|
||||
}
|
||||
|
||||
|
|
@ -315,49 +314,31 @@ pub fn rust_src(build: &Build) {
|
|||
"mk"
|
||||
];
|
||||
|
||||
// Exclude paths matching these wildcard expressions
|
||||
let excludes = [
|
||||
// exclude-vcs
|
||||
"CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules", ".gitattributes", ".cvsignore",
|
||||
".svn", ".arch-ids", "{arch}", "=RELEASE-ID", "=meta-update", "=update", ".bzr",
|
||||
".bzrignore", ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
|
||||
// extensions
|
||||
"*~", "*.pyc",
|
||||
// misc
|
||||
"llvm/test/*/*.ll",
|
||||
"llvm/test/*/*.td",
|
||||
"llvm/test/*/*.s",
|
||||
"llvm/test/*/*/*.ll",
|
||||
"llvm/test/*/*/*.td",
|
||||
"llvm/test/*/*/*.s"
|
||||
];
|
||||
|
||||
// Construct a set of regexes for efficiently testing whether paths match one of the above
|
||||
// expressions.
|
||||
let regex_set = t!(RegexSet::new(
|
||||
// This converts a wildcard expression to a regex
|
||||
excludes.iter().map(|&s| {
|
||||
// Prefix ensures that matching starts on a path separator boundary
|
||||
r"^(.*[\\/])?".to_owned() + (
|
||||
// Escape the expression to produce a regex matching exactly that string
|
||||
"e(s)
|
||||
// Replace slashes with a pattern matching either forward or backslash
|
||||
.replace(r"/", r"[\\/]")
|
||||
// Replace wildcards with a pattern matching a single path segment, ie. containing
|
||||
// no slashes.
|
||||
.replace(r"\*", r"[^\\/]*")
|
||||
// Suffix anchors to the end of the path
|
||||
) + "$"
|
||||
})
|
||||
));
|
||||
|
||||
// Create a filter which skips files which match the regex set or contain invalid unicode
|
||||
let filter_fn = move |path: &Path| {
|
||||
if let Some(path) = path.to_str() {
|
||||
!regex_set.is_match(path)
|
||||
} else {
|
||||
false
|
||||
let spath = match path.to_str() {
|
||||
Some(path) => path,
|
||||
None => return false,
|
||||
};
|
||||
if spath.ends_with("~") || spath.ends_with(".pyc") {
|
||||
return false
|
||||
}
|
||||
if spath.contains("llvm/test") || spath.contains("llvm\\test") {
|
||||
if spath.ends_with(".ll") ||
|
||||
spath.ends_with(".td") ||
|
||||
spath.ends_with(".s") {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
let excludes = [
|
||||
"CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
|
||||
".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
|
||||
"=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore",
|
||||
".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
|
||||
];
|
||||
!path.iter()
|
||||
.map(|s| s.to_str().unwrap())
|
||||
.any(|s| excludes.contains(&s))
|
||||
};
|
||||
|
||||
// Copy the directories using our filter
|
||||
|
|
@ -418,7 +399,7 @@ fn chmod(_path: &Path, _perms: u32) {}
|
|||
|
||||
// We have to run a few shell scripts, which choke quite a bit on both `\`
|
||||
// characters and on `C:\` paths, so normalize both of them away.
|
||||
fn sanitize_sh(path: &Path) -> String {
|
||||
pub fn sanitize_sh(path: &Path) -> String {
|
||||
let path = path.to_str().unwrap().replace("\\", "/");
|
||||
return change_drive(&path).unwrap_or(path);
|
||||
|
||||
|
|
|
|||
61
src/bootstrap/install.rs
Normal file
61
src/bootstrap/install.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation of the install aspects of the compiler.
|
||||
//!
|
||||
//! This module is responsible for installing the standard library,
|
||||
//! compiler, and documentation.
|
||||
|
||||
use std::fs;
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use Build;
|
||||
use dist::{package_vers, sanitize_sh, tmpdir};
|
||||
|
||||
/// Installs everything.
|
||||
pub fn install(build: &Build, stage: u32, host: &str) {
|
||||
let prefix = build.config.prefix.as_ref().clone().map(|x| Path::new(x))
|
||||
.unwrap_or(Path::new("/usr/local"));
|
||||
let docdir = build.config.docdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
|
||||
.unwrap_or(Cow::Owned(prefix.join("share/doc/rust")));
|
||||
let libdir = build.config.libdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
|
||||
.unwrap_or(Cow::Owned(prefix.join("lib")));
|
||||
let mandir = build.config.mandir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
|
||||
.unwrap_or(Cow::Owned(prefix.join("share/man")));
|
||||
let empty_dir = build.out.join("tmp/empty_dir");
|
||||
t!(fs::create_dir_all(&empty_dir));
|
||||
if build.config.docs {
|
||||
install_sh(&build, "docs", "rust-docs", stage, host, prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
}
|
||||
install_sh(&build, "std", "rust-std", stage, host, prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
install_sh(&build, "rustc", "rustc", stage, host, prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
t!(fs::remove_dir_all(&empty_dir));
|
||||
}
|
||||
|
||||
fn install_sh(build: &Build, package: &str, name: &str, stage: u32, host: &str,
|
||||
prefix: &Path, docdir: &Path, libdir: &Path, mandir: &Path, empty_dir: &Path) {
|
||||
println!("Install {} stage{} ({})", package, stage, host);
|
||||
let package_name = format!("{}-{}-{}", name, package_vers(build), host);
|
||||
|
||||
let mut cmd = Command::new("sh");
|
||||
cmd.current_dir(empty_dir)
|
||||
.arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
|
||||
.arg(format!("--prefix={}", sanitize_sh(prefix)))
|
||||
.arg(format!("--docdir={}", sanitize_sh(docdir)))
|
||||
.arg(format!("--libdir={}", sanitize_sh(libdir)))
|
||||
.arg(format!("--mandir={}", sanitize_sh(mandir)))
|
||||
.arg("--disable-ldconfig");
|
||||
build.run(&mut cmd);
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ extern crate md5;
|
|||
extern crate num_cpus;
|
||||
extern crate rustc_serialize;
|
||||
extern crate toml;
|
||||
extern crate regex;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
|
@ -62,6 +61,7 @@ mod config;
|
|||
mod dist;
|
||||
mod doc;
|
||||
mod flags;
|
||||
mod install;
|
||||
mod native;
|
||||
mod sanity;
|
||||
mod step;
|
||||
|
|
@ -220,14 +220,14 @@ impl Build {
|
|||
sanity::check(self);
|
||||
self.verbose("collecting channel variables");
|
||||
channel::collect(self);
|
||||
// If local-rust is the same as the current version, then force a local-rebuild
|
||||
// If local-rust is the same major.minor as the current version, then force a local-rebuild
|
||||
let local_version_verbose = output(
|
||||
Command::new(&self.rustc).arg("--version").arg("--verbose"));
|
||||
let local_release = local_version_verbose
|
||||
.lines().filter(|x| x.starts_with("release:"))
|
||||
.next().unwrap().trim_left_matches("release:").trim();
|
||||
if local_release == self.release {
|
||||
self.verbose(&format!("auto-detected local-rebuild {}", self.release));
|
||||
if local_release.split('.').take(2).eq(self.release.split('.').take(2)) {
|
||||
self.verbose(&format!("auto-detected local-rebuild {}", local_release));
|
||||
self.local_rebuild = true;
|
||||
}
|
||||
self.verbose("updating submodules");
|
||||
|
|
@ -243,7 +243,14 @@ impl Build {
|
|||
// Almost all of these are simple one-liners that shell out to the
|
||||
// corresponding functionality in the extra modules, where more
|
||||
// documentation can be found.
|
||||
for target in step::all(self) {
|
||||
let steps = step::all(self);
|
||||
|
||||
self.verbose("bootstrap build plan:");
|
||||
for step in &steps {
|
||||
self.verbose(&format!("{:?}", step));
|
||||
}
|
||||
|
||||
for target in steps {
|
||||
let doc_out = self.out.join(&target.target).join("doc");
|
||||
match target.src {
|
||||
Llvm { _dummy } => {
|
||||
|
|
@ -446,6 +453,8 @@ impl Build {
|
|||
DistStd { compiler } => dist::std(self, &compiler, target.target),
|
||||
DistSrc { _dummy } => dist::rust_src(self),
|
||||
|
||||
Install { stage } => install::install(self, stage, target.target),
|
||||
|
||||
DebuggerScripts { stage } => {
|
||||
let compiler = Compiler::new(stage, target.target);
|
||||
dist::debugger_scripts(self,
|
||||
|
|
@ -550,12 +559,23 @@ impl Build {
|
|||
continue
|
||||
}
|
||||
|
||||
// `submodule.path` is the relative path to a submodule (from the repository root)
|
||||
// `submodule_path` is the path to a submodule from the cwd
|
||||
|
||||
// use `submodule.path` when e.g. executing a submodule specific command from the
|
||||
// repository root
|
||||
// use `submodule_path` when e.g. executing a normal git command for the submodule
|
||||
// (set via `current_dir`)
|
||||
let submodule_path = self.src.join(submodule.path);
|
||||
|
||||
match submodule.state {
|
||||
State::MaybeDirty => {
|
||||
// drop staged changes
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
|
||||
self.run(git().current_dir(&submodule_path)
|
||||
.args(&["reset", "--hard"]));
|
||||
// drops unstaged changes
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
|
||||
self.run(git().current_dir(&submodule_path)
|
||||
.args(&["clean", "-fdx"]));
|
||||
},
|
||||
State::NotInitialized => {
|
||||
self.run(git_submodule().arg("init").arg(submodule.path));
|
||||
|
|
@ -564,8 +584,10 @@ impl Build {
|
|||
State::OutOfSync => {
|
||||
// drops submodule commits that weren't reported to the (outer) git repository
|
||||
self.run(git_submodule().arg("update").arg(submodule.path));
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
|
||||
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
|
||||
self.run(git().current_dir(&submodule_path)
|
||||
.args(&["reset", "--hard"]));
|
||||
self.run(git().current_dir(&submodule_path)
|
||||
.args(&["clean", "-fdx"]));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -627,6 +649,7 @@ impl Build {
|
|||
.env("RUSTC_REAL", self.compiler_path(compiler))
|
||||
.env("RUSTC_STAGE", stage.to_string())
|
||||
.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string())
|
||||
.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string())
|
||||
.env("RUSTC_CODEGEN_UNITS",
|
||||
self.config.rust_codegen_units.to_string())
|
||||
.env("RUSTC_DEBUG_ASSERTIONS",
|
||||
|
|
@ -640,7 +663,7 @@ impl Build {
|
|||
.env("RUSTDOC_REAL", self.rustdoc(compiler))
|
||||
.env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
|
||||
|
||||
self.add_bootstrap_key(compiler, &mut cargo);
|
||||
self.add_bootstrap_key(&mut cargo);
|
||||
|
||||
// Specify some various options for build scripts used throughout
|
||||
// the build.
|
||||
|
|
@ -652,12 +675,6 @@ impl Build {
|
|||
.env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
|
||||
}
|
||||
|
||||
// If we're building for OSX, inform the compiler and the linker that
|
||||
// we want to build a compiler runnable on 10.7
|
||||
if target.contains("apple-darwin") {
|
||||
cargo.env("MACOSX_DEPLOYMENT_TARGET", "10.7");
|
||||
}
|
||||
|
||||
// Environment variables *required* needed throughout the build
|
||||
//
|
||||
// FIXME: should update code to not require this env var
|
||||
|
|
@ -855,16 +872,11 @@ impl Build {
|
|||
}
|
||||
|
||||
/// Adds the compiler's bootstrap key to the environment of `cmd`.
|
||||
fn add_bootstrap_key(&self, compiler: &Compiler, cmd: &mut Command) {
|
||||
// In stage0 we're using a previously released stable compiler, so we
|
||||
// use the stage0 bootstrap key. Otherwise we use our own build's
|
||||
// bootstrap key.
|
||||
let bootstrap_key = if compiler.is_snapshot(self) && !self.local_rebuild {
|
||||
&self.bootstrap_key_stage0
|
||||
} else {
|
||||
&self.bootstrap_key
|
||||
};
|
||||
cmd.env("RUSTC_BOOTSTRAP_KEY", bootstrap_key);
|
||||
fn add_bootstrap_key(&self, cmd: &mut Command) {
|
||||
cmd.env("RUSTC_BOOTSTRAP", "");
|
||||
// FIXME: Transitionary measure to bootstrap using the old bootstrap logic.
|
||||
// Remove this once the bootstrap compiler uses the new login in Issue #36548.
|
||||
cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239");
|
||||
}
|
||||
|
||||
/// Returns the compiler's libdir where it stores the dynamic libraries that
|
||||
|
|
@ -926,7 +938,6 @@ impl Build {
|
|||
// LLVM/jemalloc/etc are all properly compiled.
|
||||
if target.contains("apple-darwin") {
|
||||
base.push("-stdlib=libc++".into());
|
||||
base.push("-mmacosx-version-min=10.7".into());
|
||||
}
|
||||
// This is a hack, because newer binutils broke things on some vms/distros
|
||||
// (i.e., linking against unknown relocs disabled by the following flag)
|
||||
|
|
@ -950,7 +961,11 @@ impl Build {
|
|||
/// Returns the path to the C++ compiler for the target specified, may panic
|
||||
/// if no C++ compiler was configured for the target.
|
||||
fn cxx(&self, target: &str) -> &Path {
|
||||
self.cxx[target].path()
|
||||
match self.cxx.get(target) {
|
||||
Some(p) => p.path(),
|
||||
None => panic!("\n\ntarget `{}` is not configured as a host,
|
||||
only as a target\n\n", target),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns flags to pass to the compiler to generate code for `target`.
|
||||
|
|
@ -963,7 +978,8 @@ impl Build {
|
|||
// than an entry here.
|
||||
|
||||
let mut base = Vec::new();
|
||||
if target != self.config.build && !target.contains("msvc") {
|
||||
if target != self.config.build && !target.contains("msvc") &&
|
||||
!target.contains("emscripten") {
|
||||
base.push(format!("-Clinker={}", self.cc(target).display()));
|
||||
}
|
||||
return base
|
||||
|
|
@ -971,7 +987,8 @@ impl Build {
|
|||
|
||||
/// Returns the "musl root" for this `target`, if defined
|
||||
fn musl_root(&self, target: &str) -> Option<&Path> {
|
||||
self.config.target_config[target].musl_root.as_ref()
|
||||
self.config.target_config.get(target)
|
||||
.and_then(|t| t.musl_root.as_ref())
|
||||
.or(self.config.musl_root.as_ref())
|
||||
.map(|p| &**p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,12 @@ check-cargotest:
|
|||
$(Q)$(BOOTSTRAP) --step check-cargotest
|
||||
dist:
|
||||
$(Q)$(BOOTSTRAP) --step dist
|
||||
install:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
$(Q)echo "'sudo make install' is not supported currently."
|
||||
else
|
||||
$(Q)$(BOOTSTRAP) --step install
|
||||
endif
|
||||
tidy:
|
||||
$(Q)$(BOOTSTRAP) --step check-tidy --stage 0
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@
|
|||
//! LLVM and compiler-rt are essentially just wired up to everything else to
|
||||
//! ensure that they're always in place if needed.
|
||||
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::fs::{self, File};
|
||||
|
||||
use build_helper::output;
|
||||
use cmake;
|
||||
|
|
@ -43,11 +44,17 @@ pub fn llvm(build: &Build, target: &str) {
|
|||
// artifacts are missing) then we keep going, otherwise we bail out.
|
||||
let dst = build.llvm_out(target);
|
||||
let stamp = build.src.join("src/rustllvm/llvm-auto-clean-trigger");
|
||||
let mut stamp_contents = String::new();
|
||||
t!(t!(File::open(&stamp)).read_to_string(&mut stamp_contents));
|
||||
let done_stamp = dst.join("llvm-finished-building");
|
||||
build.clear_if_dirty(&dst, &stamp);
|
||||
if fs::metadata(&done_stamp).is_ok() {
|
||||
return
|
||||
if done_stamp.exists() {
|
||||
let mut done_contents = String::new();
|
||||
t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));
|
||||
if done_contents == stamp_contents {
|
||||
return
|
||||
}
|
||||
}
|
||||
drop(fs::remove_dir_all(&dst));
|
||||
|
||||
println!("Building LLVM for {}", target);
|
||||
|
||||
|
|
@ -65,7 +72,7 @@ pub fn llvm(build: &Build, target: &str) {
|
|||
.out_dir(&dst)
|
||||
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
|
||||
.define("LLVM_ENABLE_ASSERTIONS", assertions)
|
||||
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
|
||||
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
|
||||
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
|
||||
.define("LLVM_INCLUDE_TESTS", "OFF")
|
||||
.define("LLVM_INCLUDE_DOCS", "OFF")
|
||||
|
|
@ -73,7 +80,9 @@ pub fn llvm(build: &Build, target: &str) {
|
|||
.define("WITH_POLLY", "OFF")
|
||||
.define("LLVM_ENABLE_TERMINFO", "OFF")
|
||||
.define("LLVM_ENABLE_LIBEDIT", "OFF")
|
||||
.define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string());
|
||||
.define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string())
|
||||
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
|
||||
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
|
||||
|
||||
if target.starts_with("i686") {
|
||||
cfg.define("LLVM_BUILD_32_BITS", "ON");
|
||||
|
|
@ -86,9 +95,7 @@ pub fn llvm(build: &Build, target: &str) {
|
|||
// actually exists most of the time in normal installs of LLVM.
|
||||
let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
|
||||
cfg.define("CMAKE_CROSSCOMPILING", "True")
|
||||
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
|
||||
.define("LLVM_TABLEGEN", &host)
|
||||
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
|
||||
.define("LLVM_TABLEGEN", &host);
|
||||
}
|
||||
|
||||
// MSVC handles compiler business itself
|
||||
|
|
@ -114,7 +121,7 @@ pub fn llvm(build: &Build, target: &str) {
|
|||
// tools and libs on all platforms.
|
||||
cfg.build();
|
||||
|
||||
t!(File::create(&done_stamp));
|
||||
t!(t!(File::create(&done_stamp)).write_all(stamp_contents.as_bytes()));
|
||||
}
|
||||
|
||||
fn check_llvm_version(build: &Build, llvm_config: &Path) {
|
||||
|
|
|
|||
|
|
@ -40,17 +40,23 @@ pub fn check(build: &mut Build) {
|
|||
panic!("PATH contains invalid character '\"'");
|
||||
}
|
||||
}
|
||||
let have_cmd = |cmd: &OsStr| {
|
||||
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
|
||||
if fs::metadata(&path).is_ok() ||
|
||||
fs::metadata(path.with_extension("exe")).is_ok() {
|
||||
return Some(path);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut need_cmd = |cmd: &OsStr| {
|
||||
if !checked.insert(cmd.to_owned()) {
|
||||
return
|
||||
}
|
||||
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
|
||||
if fs::metadata(&path).is_ok() ||
|
||||
fs::metadata(path.with_extension("exe")).is_ok() {
|
||||
return
|
||||
}
|
||||
if have_cmd(cmd).is_none() {
|
||||
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
|
||||
}
|
||||
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
|
||||
};
|
||||
|
||||
// If we've got a git directory we're gona need git to update
|
||||
|
|
@ -75,8 +81,13 @@ pub fn check(build: &mut Build) {
|
|||
|
||||
need_cmd("python".as_ref());
|
||||
|
||||
// If a manual nodejs was added to the config,
|
||||
// of if a nodejs install is detected through config, use it.
|
||||
// Look for the nodejs command, needed for emscripten testing
|
||||
if let Some(node) = have_cmd("node".as_ref()) {
|
||||
build.config.nodejs = Some(node);
|
||||
} else if let Some(node) = have_cmd("nodejs".as_ref()) {
|
||||
build.config.nodejs = Some(node);
|
||||
}
|
||||
|
||||
if let Some(ref s) = build.config.nodejs {
|
||||
need_cmd(s.as_ref());
|
||||
}
|
||||
|
|
@ -84,6 +95,13 @@ pub fn check(build: &mut Build) {
|
|||
// We're gonna build some custom C code here and there, host triples
|
||||
// also build some C++ shims for LLVM so we need a C++ compiler.
|
||||
for target in build.config.target.iter() {
|
||||
// On emscripten we don't actually need the C compiler to just
|
||||
// build the target artifacts, only for testing. For the sake
|
||||
// of easier bot configuration, just skip detection.
|
||||
if target.contains("emscripten") {
|
||||
continue;
|
||||
}
|
||||
|
||||
need_cmd(build.cc(target).as_ref());
|
||||
if let Some(ar) = build.ar(target) {
|
||||
need_cmd(ar.as_ref());
|
||||
|
|
@ -93,6 +111,14 @@ pub fn check(build: &mut Build) {
|
|||
need_cmd(build.cxx(host).as_ref());
|
||||
}
|
||||
|
||||
// The msvc hosts don't use jemalloc, turn it off globally to
|
||||
// avoid packaging the dummy liballoc_jemalloc on that platform.
|
||||
for host in build.config.host.iter() {
|
||||
if host.contains("msvc") {
|
||||
build.config.use_jemalloc = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Externally configured LLVM requires FileCheck to exist
|
||||
let filecheck = build.llvm_filecheck(&build.config.build);
|
||||
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
|
||||
|
|
@ -100,15 +126,6 @@ pub fn check(build: &mut Build) {
|
|||
}
|
||||
|
||||
for target in build.config.target.iter() {
|
||||
// Either can't build or don't want to run jemalloc on these targets
|
||||
if target.contains("rumprun") ||
|
||||
target.contains("bitrig") ||
|
||||
target.contains("openbsd") ||
|
||||
target.contains("msvc") ||
|
||||
target.contains("emscripten") {
|
||||
build.config.use_jemalloc = false;
|
||||
}
|
||||
|
||||
// Can't compile for iOS unless we're on OSX
|
||||
if target.contains("apple-ios") &&
|
||||
!build.config.build.contains("apple-darwin") {
|
||||
|
|
@ -129,8 +146,8 @@ pub fn check(build: &mut Build) {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
panic!("when targeting MUSL either the build.musl-root \
|
||||
option or the target.$TARGET.musl-root one must \
|
||||
panic!("when targeting MUSL either the rust.musl-root \
|
||||
option or the target.$TARGET.musl-root option must \
|
||||
be specified in config.toml")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,9 @@ macro_rules! targets {
|
|||
(dist_std, DistStd { compiler: Compiler<'a> }),
|
||||
(dist_src, DistSrc { _dummy: () }),
|
||||
|
||||
// install target
|
||||
(install, Install { stage: u32 }),
|
||||
|
||||
// Misc targets
|
||||
(android_copy_libs, AndroidCopyLibs { compiler: Compiler<'a> }),
|
||||
}
|
||||
|
|
@ -171,6 +174,8 @@ targets!(define_source);
|
|||
/// into a topologically sorted list which when executed left-to-right will
|
||||
/// correctly sequence the entire build.
|
||||
pub fn all(build: &Build) -> Vec<Step> {
|
||||
build.verbose("inferred build steps:");
|
||||
|
||||
let mut ret = Vec::new();
|
||||
let mut all = HashSet::new();
|
||||
for target in top_level(build) {
|
||||
|
|
@ -184,6 +189,7 @@ pub fn all(build: &Build) -> Vec<Step> {
|
|||
set: &mut HashSet<Step<'a>>) {
|
||||
if set.insert(target.clone()) {
|
||||
for dep in target.deps(build) {
|
||||
build.verbose(&format!("{:?}\n -> {:?}", target, dep));
|
||||
fill(build, &dep, ret, set);
|
||||
}
|
||||
ret.push(target.clone());
|
||||
|
|
@ -246,8 +252,7 @@ fn top_level(build: &Build) -> Vec<Step> {
|
|||
}
|
||||
}
|
||||
|
||||
return targets
|
||||
|
||||
targets
|
||||
}
|
||||
|
||||
fn add_steps<'a>(build: &'a Build,
|
||||
|
|
@ -415,7 +420,6 @@ impl<'a> Step<'a> {
|
|||
self.check_crate_std(compiler),
|
||||
self.check_crate_test(compiler),
|
||||
self.check_debuginfo(compiler),
|
||||
self.dist(stage),
|
||||
];
|
||||
|
||||
// If we're testing the build triple, then we know we can
|
||||
|
|
@ -460,9 +464,12 @@ impl<'a> Step<'a> {
|
|||
// misc
|
||||
self.check_linkcheck(stage),
|
||||
self.check_tidy(stage),
|
||||
|
||||
// can we make the distributables?
|
||||
self.dist(stage),
|
||||
]);
|
||||
}
|
||||
return base
|
||||
base
|
||||
}
|
||||
Source::CheckLinkcheck { stage } => {
|
||||
vec![self.tool_linkchecker(stage), self.doc(stage)]
|
||||
|
|
@ -483,7 +490,6 @@ impl<'a> Step<'a> {
|
|||
Source::CheckCodegenUnits { compiler } |
|
||||
Source::CheckIncremental { compiler } |
|
||||
Source::CheckUi { compiler } |
|
||||
Source::CheckRustdoc { compiler } |
|
||||
Source::CheckPretty { compiler } |
|
||||
Source::CheckCFail { compiler } |
|
||||
Source::CheckRPassValgrind { compiler } |
|
||||
|
|
@ -506,6 +512,7 @@ impl<'a> Step<'a> {
|
|||
self.debugger_scripts(compiler.stage),
|
||||
]
|
||||
}
|
||||
Source::CheckRustdoc { compiler } |
|
||||
Source::CheckRPassFull { compiler } |
|
||||
Source::CheckRFailFull { compiler } |
|
||||
Source::CheckCFailFull { compiler } |
|
||||
|
|
@ -517,7 +524,7 @@ impl<'a> Step<'a> {
|
|||
self.target(compiler.host).tool_compiletest(compiler.stage)]
|
||||
}
|
||||
Source::CheckDocs { compiler } => {
|
||||
vec![self.libstd(compiler)]
|
||||
vec![self.libtest(compiler)]
|
||||
}
|
||||
Source::CheckErrorIndex { compiler } => {
|
||||
vec![self.libstd(compiler),
|
||||
|
|
@ -585,7 +592,11 @@ impl<'a> Step<'a> {
|
|||
base.push(target.dist_std(compiler));
|
||||
}
|
||||
}
|
||||
return base
|
||||
base
|
||||
}
|
||||
|
||||
Source::Install { stage } => {
|
||||
vec![self.dist(stage)]
|
||||
}
|
||||
|
||||
Source::AndroidCopyLibs { compiler } => {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ pub fn run_silent(cmd: &mut Command) {
|
|||
};
|
||||
if !status.success() {
|
||||
fail(&format!("command did not execute successfully: {:?}\n\
|
||||
expected success, got: {}", cmd, status));
|
||||
expected success, got: {}",
|
||||
cmd,
|
||||
status));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +67,9 @@ pub fn output(cmd: &mut Command) -> String {
|
|||
};
|
||||
if !output.status.success() {
|
||||
panic!("command did not execute successfully: {:?}\n\
|
||||
expected success, got: {}", cmd, output.status);
|
||||
expected success, got: {}",
|
||||
cmd,
|
||||
output.status);
|
||||
}
|
||||
String::from_utf8(output.stdout).unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 8598065bd965d9713bfafb6c1e766d63a7b17b89
|
||||
Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356
|
||||
|
|
@ -4,7 +4,7 @@ Concurrency and parallelism are incredibly important topics in computer
|
|||
science, and are also a hot topic in industry today. Computers are gaining more
|
||||
and more cores, yet many programmers aren't prepared to fully utilize them.
|
||||
|
||||
Rust's memory safety features also apply to its concurrency story too. Even
|
||||
Rust's memory safety features also apply to its concurrency story. Even
|
||||
concurrent Rust programs must be memory safe, having no data races. Rust's type
|
||||
system is up to the task, and gives you powerful ways to reason about
|
||||
concurrent code at compile time.
|
||||
|
|
@ -281,8 +281,8 @@ And... still gives us an error.
|
|||
```
|
||||
|
||||
`Arc<T>` by default has immutable contents. It allows the _sharing_ of data
|
||||
between threads, but shared mutable data is unsafe and when threads are
|
||||
involved can cause data races!
|
||||
between threads, but shared mutable data is unsafe—and when threads are
|
||||
involved—can cause data races!
|
||||
|
||||
|
||||
Usually when we wish to make something in an immutable position mutable, we use
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% `const` and `static`
|
||||
% const and static
|
||||
|
||||
Rust has a way of defining constants with the `const` keyword:
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ foo(&counted);
|
|||
All we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the
|
||||
`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
|
||||
didn’t change, but works just as well with either type. This example has two
|
||||
conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
|
||||
conversions: `&Rc<String>` to `&String` and then `&String` to `&str`. Rust will do
|
||||
this as many times as possible until the types match.
|
||||
|
||||
Another very common implementation provided by the standard library is:
|
||||
|
|
|
|||
|
|
@ -166,12 +166,22 @@ you can find the Rust executables in a directory like
|
|||
`"C:\Program Files\Rust stable GNU 1.x\bin"`.
|
||||
|
||||
Rust does not do its own linking, and so you’ll need to have a linker
|
||||
installed. Doing so will depend on your specific system, consult its
|
||||
documentation for more details.
|
||||
installed. Doing so will depend on your specific system. For
|
||||
Linux-based systems, Rust will attempt to call `cc` for linking. On
|
||||
`windows-msvc` (Rust built on Windows with Microsoft Visual Studio),
|
||||
this depends on having [Microsoft Visual C++ Build Tools][msvbt]
|
||||
installed. These do not need to be in `%PATH%` as `rustc` will find
|
||||
them automatically. In general, if you have your linker in a
|
||||
non-traditional location you can call `rustc
|
||||
linker=/path/to/cc`, where `/path/to/cc` should point to your linker path.
|
||||
|
||||
If not, there are a number of places where we can get help. The easiest is
|
||||
[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] and for
|
||||
general discussion [the #rust IRC channel on irc.mozilla.org][irc], which we
|
||||
[msvbt]: http://landinghub.visualstudio.com/visual-cpp-build-tools
|
||||
|
||||
If you are still stuck, there are a number of places where we can get
|
||||
help. The easiest is
|
||||
[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners]
|
||||
and for general discussion
|
||||
[the #rust IRC channel on irc.mozilla.org][irc], which we
|
||||
can access through [Mibbit][mibbit]. Then we'll be chatting with other
|
||||
Rustaceans (a silly nickname we call ourselves) who can help us out. Other great
|
||||
resources include [the user’s forum][users] and [Stack Overflow][stackoverflow].
|
||||
|
|
@ -230,12 +240,13 @@ $ cd hello_world
|
|||
|
||||
## Writing and Running a Rust Program
|
||||
|
||||
Next, make a new source file and call it *main.rs*. Rust files always end
|
||||
in a *.rs* extension. If you’re using more than one word in your filename, use
|
||||
an underscore to separate them; for example, you'd use *hello_world.rs* rather
|
||||
than *helloworld.rs*.
|
||||
We need to create a source file for our Rust program. Rust files always end
|
||||
in a *.rs* extension. If you are using more than one word in your filename,
|
||||
use an underscore to separate them; for example, you would use
|
||||
*my_program.rs* rather than *myprogram.rs*.
|
||||
|
||||
Now open the *main.rs* file you just created, and type the following code:
|
||||
Now, make a new file and call it *main.rs*. Open the file and type
|
||||
the following code:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
|
@ -494,6 +505,9 @@ $ cargo run
|
|||
Hello, world!
|
||||
```
|
||||
|
||||
The `run` command comes in handy when you need to rapidly iterate on a
|
||||
project.
|
||||
|
||||
Notice that this example didn’t re-build the project. Cargo figured out that
|
||||
the file hasn’t changed, and so it just ran the binary. If you'd modified your
|
||||
source code, Cargo would have rebuilt the project before running it, and you
|
||||
|
|
|
|||
|
|
@ -56,9 +56,7 @@ $ cargo build
|
|||
Excellent! Open up your `src/main.rs` again. We’ll be writing all of
|
||||
our code in this file.
|
||||
|
||||
Before we move on, let me show you one more Cargo command: `run`. `cargo run`
|
||||
is kind of like `cargo build`, but it also then runs the produced executable.
|
||||
Try it out:
|
||||
Remember the `run` command from last chapter? Try it out again here:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
|
|
@ -67,9 +65,8 @@ $ cargo run
|
|||
Hello, world!
|
||||
```
|
||||
|
||||
Great! The `run` command comes in handy when you need to rapidly iterate on a
|
||||
project. Our game is such a project, we need to quickly test each
|
||||
iteration before moving on to the next one.
|
||||
Great! Our game is just the kind of project `run` is good for: we need
|
||||
to quickly test each iteration before moving on to the next one.
|
||||
|
||||
# Processing a Guess
|
||||
|
||||
|
|
@ -279,7 +276,7 @@ displaying the message.
|
|||
[expect]: ../std/result/enum.Result.html#method.expect
|
||||
[panic]: error-handling.html
|
||||
|
||||
If we leave off calling this method, our program will compile, but
|
||||
If we do not call `expect()`, our program will compile, but
|
||||
we’ll get a warning:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -50,29 +50,94 @@ complicated. For example, imagine this set of operations:
|
|||
4. You decide to use the resource.
|
||||
|
||||
Uh oh! Your reference is pointing to an invalid resource. This is called a
|
||||
dangling pointer or ‘use after free’, when the resource is memory.
|
||||
dangling pointer or ‘use after free’, when the resource is memory. A small
|
||||
example of such a situation would be:
|
||||
|
||||
```rust,compile_fail
|
||||
let r; // Introduce reference: r
|
||||
{
|
||||
let i = 1; // Introduce scoped value: i
|
||||
r = &i; // Store reference of i in r
|
||||
} // i goes out of scope and is dropped.
|
||||
|
||||
println!("{}", r); // r still refers to i
|
||||
```
|
||||
|
||||
To fix this, we have to make sure that step four never happens after step
|
||||
three. The ownership system in Rust does this through a concept called
|
||||
lifetimes, which describe the scope that a reference is valid for.
|
||||
three. In the small example above the Rust compiler is able to report the issue
|
||||
as it can see the lifetimes of the various values in the function.
|
||||
|
||||
When we have a function that takes an argument by reference, we can be
|
||||
implicit or explicit about the lifetime of the reference:
|
||||
When we have a function that takes arguments by reference the situation becomes
|
||||
more complex. Consider the following example:
|
||||
|
||||
```rust
|
||||
// implicit
|
||||
fn foo(x: &i32) {
|
||||
```rust,compile_fail,E0106
|
||||
fn skip_prefix(line: &str, prefix: &str) -> &str {
|
||||
// ...
|
||||
# line
|
||||
}
|
||||
|
||||
// explicit
|
||||
fn bar<'a>(x: &'a i32) {
|
||||
let line = "lang:en=Hello World!";
|
||||
let lang = "en";
|
||||
|
||||
let v;
|
||||
{
|
||||
let p = format!("lang:{}=", lang); // -+ p goes into scope
|
||||
v = skip_prefix(line, p.as_str()); // |
|
||||
} // -+ p goes out of scope
|
||||
println!("{}", v);
|
||||
```
|
||||
|
||||
Here we have a function `skip_prefix` which takes two `&str` references
|
||||
as parameters and returns a single `&str` reference. We call it
|
||||
by passing in references to `line` and `p`: Two variables with different
|
||||
lifetimes. Now the safety of the `println!`-line depends on whether the
|
||||
reference returned by `skip_prefix` function references the still living
|
||||
`line` or the already dropped `p` string.
|
||||
|
||||
Because of the above ambiguity, Rust will refuse to compile the example
|
||||
code. To get it to compile we need to tell the compiler more about the
|
||||
lifetimes of the references. This can be done by making the lifetimes
|
||||
explicit in the function declaration:
|
||||
|
||||
```rust
|
||||
fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str {
|
||||
// ...
|
||||
# line
|
||||
}
|
||||
```
|
||||
|
||||
Let's examine the changes without going too deep into the syntax for now -
|
||||
we'll get to that later. The first change was adding the `<'a, 'b>` after the
|
||||
method name. This introduces two lifetime parameters: `'a` and `'b`. Next each
|
||||
reference in the function signature was associated with one of the lifetime
|
||||
parameters by adding the lifetime name after the `&`. This tells the compiler
|
||||
how the lifetimes between different references are related.
|
||||
|
||||
As a result the compiler is now able to deduce that the return value of
|
||||
`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v`
|
||||
reference safe to use even after the `p` goes out of scope in the original
|
||||
example.
|
||||
|
||||
In addition to the compiler being able to validate the usage of `skip_prefix`
|
||||
return value, it can also ensure that the implementation follows the contract
|
||||
established by the function declaration. This is useful especially when you are
|
||||
implementing traits that are introduced [later in the book][traits].
|
||||
|
||||
**Note** It's important to understand that lifetime annotations are
|
||||
_descriptive_, not _prescriptive_. This means that how long a reference is valid
|
||||
is determined by the code, not by the annotations. The annotations, however,
|
||||
give information about lifetimes to the compiler that uses them to check the
|
||||
validity of references. The compiler can do so without annotations in simple
|
||||
cases, but needs the programmers support in complex scenarios.
|
||||
|
||||
[traits]: traits.html
|
||||
|
||||
# Syntax
|
||||
|
||||
The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime
|
||||
associated with it, but the compiler lets you elide (i.e. omit, see
|
||||
["Lifetime Elision"][lifetime-elision] below) them in common cases.
|
||||
Before we get to that, though, let’s break the explicit example down:
|
||||
["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we
|
||||
get to that, though, let’s look at a short example with explicit lifetimes:
|
||||
|
||||
[lifetime-elision]: #lifetime-elision
|
||||
|
||||
|
|
@ -90,7 +155,8 @@ focus on the lifetimes aspect.
|
|||
[generics]: generics.html
|
||||
|
||||
We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
|
||||
`'a`. If we had two reference parameters, it would look like this:
|
||||
`'a`. If we had two reference parameters with different lifetimes, it would
|
||||
look like this:
|
||||
|
||||
|
||||
```rust,ignore
|
||||
|
|
|
|||
|
|
@ -57,13 +57,13 @@ of scope at the end of `foo()`, Rust will clean up everything related to the
|
|||
vector, even the heap-allocated memory. This happens deterministically, at the
|
||||
end of the scope.
|
||||
|
||||
We'll cover [vectors] in detail later in this chapter; we only use them
|
||||
We covered [vectors] in the previous chapter; we use them
|
||||
here as an example of a type that allocates space on the heap at runtime. They
|
||||
behave like [arrays], except their size may change by `push()`ing more
|
||||
elements onto them.
|
||||
|
||||
Vectors have a [generic type][generics] `Vec<T>`, so in this example `v` will have type
|
||||
`Vec<i32>`. We'll cover generics in detail later in this chapter.
|
||||
`Vec<i32>`. We'll cover [generics] in detail in a later chapter.
|
||||
|
||||
[arrays]: primitive-types.html#arrays
|
||||
[vectors]: vectors.html
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ fn main() {
|
|||
return v.iter().fold(0, |a, &b| a + b);
|
||||
}
|
||||
// Borrow two vectors and sum them.
|
||||
// This kind of borrowing does not allow mutation to the borrowed.
|
||||
// This kind of borrowing does not allow mutation through the borrowed reference.
|
||||
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
|
||||
// do stuff with v1 and v2
|
||||
let s1 = sum_vec(v1);
|
||||
|
|
@ -240,7 +240,7 @@ fn main() {
|
|||
|
||||
In other words, the mutable borrow is held through the rest of our example. What
|
||||
we want is for the mutable borrow by `y` to end so that the resource can be
|
||||
returned to the owner, `x`. `x` can then provide a immutable borrow to `println!`.
|
||||
returned to the owner, `x`. `x` can then provide an immutable borrow to `println!`.
|
||||
In Rust, borrowing is tied to the scope that the borrow is valid for. And our
|
||||
scopes look like this:
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@
|
|||
* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`).
|
||||
* `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`).
|
||||
* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures].
|
||||
* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions].
|
||||
* `.` (`expr.ident`): member access. See [Structs], [Method Syntax].
|
||||
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
|
||||
* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)].
|
||||
|
|
@ -159,6 +158,10 @@
|
|||
* `/*!…*/`: inner block doc comment. See [Comments].
|
||||
* `/**…*/`: outer block doc comment. See [Comments].
|
||||
|
||||
<!-- Special types -->
|
||||
|
||||
* `!`: always empty Never type. See [Diverging Functions].
|
||||
|
||||
<!-- Various things involving parens and tuples -->
|
||||
|
||||
* `()`: empty tuple (*a.k.a.* unit), both literal and type.
|
||||
|
|
|
|||
|
|
@ -380,9 +380,9 @@ the `tests` directory.
|
|||
|
||||
# The `tests` directory
|
||||
|
||||
Each file in `tests/*.rs` directory is treated as individual crate.
|
||||
So, to write an integration test, let's make a `tests` directory, and
|
||||
put a `tests/integration_test.rs` file inside, with this as its contents:
|
||||
Each file in `tests/*.rs` directory is treated as an individual crate.
|
||||
To write an integration test, let's make a `tests` directory and
|
||||
put a `tests/integration_test.rs` file inside with this as its contents:
|
||||
|
||||
```rust,ignore
|
||||
extern crate adder;
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ let result = f.write(buf);
|
|||
|
||||
We need to `use` the `Write` trait first:
|
||||
|
||||
```rust,ignore
|
||||
```rust,no_run
|
||||
use std::io::Write;
|
||||
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% `type` Aliases
|
||||
% Type Aliases
|
||||
|
||||
The `type` keyword lets you declare an alias of another type:
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ Could not compile `hello_world`.
|
|||
|
||||
Rust will not let us use a value that has not been initialized.
|
||||
|
||||
Let take a minute to talk about this stuff we've added to `println!`.
|
||||
Let us take a minute to talk about this stuff we've added to `println!`.
|
||||
|
||||
If you include two curly braces (`{}`, some call them moustaches...) in your
|
||||
string to print, Rust will interpret this as a request to interpolate some sort
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@ or the <a href="https://opensource.org/licenses/MIT">MIT license</a>, at your op
|
|||
</p><p>
|
||||
This file may not be copied, modified, or distributed except according to those terms.
|
||||
</p></footer>
|
||||
<script type="text/javascript" src="playpen.js"></script>
|
||||
|
|
|
|||
|
|
@ -764,6 +764,13 @@ bound-list := bound | bound '+' bound-list
|
|||
bound := path | lifetime
|
||||
```
|
||||
|
||||
### Never type
|
||||
An empty type
|
||||
|
||||
```antlr
|
||||
never_type : "!" ;
|
||||
```
|
||||
|
||||
### Object types
|
||||
|
||||
**FIXME:** grammar?
|
||||
|
|
|
|||
|
|
@ -2472,8 +2472,7 @@ The currently implemented features of the reference compiler are:
|
|||
* - `default_type_parameter_fallback` - Allows type parameter defaults to
|
||||
influence type inference.
|
||||
|
||||
* - `stmt_expr_attributes` - Allows attributes on expressions and
|
||||
non-item statements.
|
||||
* - `stmt_expr_attributes` - Allows attributes on expressions.
|
||||
|
||||
* - `type_ascription` - Allows type ascription expressions `expr: Type`.
|
||||
|
||||
|
|
@ -3110,10 +3109,12 @@ the lambda expression captures its environment by reference, effectively
|
|||
borrowing pointers to all outer variables mentioned inside the function.
|
||||
Alternately, the compiler may infer that a lambda expression should copy or
|
||||
move values (depending on their type) from the environment into the lambda
|
||||
expression's captured environment.
|
||||
expression's captured environment. A lambda can be forced to capture its
|
||||
environment by moving values by prefixing it with the `move` keyword.
|
||||
|
||||
In this example, we define a function `ten_times` that takes a higher-order
|
||||
function argument, and we then call it with a lambda expression as an argument:
|
||||
function argument, and we then call it with a lambda expression as an argument,
|
||||
followed by a lambda expression that moves values from its environment.
|
||||
|
||||
```
|
||||
fn ten_times<F>(f: F) where F: Fn(i32) {
|
||||
|
|
@ -3123,6 +3124,9 @@ fn ten_times<F>(f: F) where F: Fn(i32) {
|
|||
}
|
||||
|
||||
ten_times(|j| println!("hello, {}", j));
|
||||
|
||||
let word = "konnichiwa".to_owned();
|
||||
ten_times(move |j| println!("{}, {}", word, j));
|
||||
```
|
||||
|
||||
### Infinite loops
|
||||
|
|
@ -3959,6 +3963,16 @@ the top-level type for the implementation of the called method. If no such metho
|
|||
found, `.deref()` is called and the compiler continues to search for the method
|
||||
implementation in the returned type `U`.
|
||||
|
||||
## The `Send` trait
|
||||
|
||||
The `Send` trait indicates that a value of this type is safe to send from one
|
||||
thread to another.
|
||||
|
||||
## The `Sync` trait
|
||||
|
||||
The `Sync` trait indicates that a value of this type is safe to share between
|
||||
multiple threads.
|
||||
|
||||
# Memory model
|
||||
|
||||
A Rust program's memory consists of a static set of *items* and a *heap*.
|
||||
|
|
@ -4009,9 +4023,9 @@ Methods that take either `self` or `Box<Self>` can optionally place them in a
|
|||
mutable variable by prefixing them with `mut` (similar to regular arguments):
|
||||
|
||||
```
|
||||
trait Changer {
|
||||
fn change(mut self) -> Self;
|
||||
fn modify(mut self: Box<Self>) -> Box<Self>;
|
||||
trait Changer: Sized {
|
||||
fn change(mut self) {}
|
||||
fn modify(mut self: Box<Self>) {}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -4064,6 +4078,12 @@ be ignored in favor of only building the artifacts specified by command line.
|
|||
Rust code into an existing non-Rust application because it will not have
|
||||
dynamic dependencies on other Rust code.
|
||||
|
||||
* `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system
|
||||
library will be produced. This is used when compiling Rust code as
|
||||
a dynamic library to be loaded from another language. This output type will
|
||||
create `*.so` files on Linux, `*.dylib` files on OSX, and `*.dll` files on
|
||||
Windows.
|
||||
|
||||
* `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be
|
||||
produced. This is used as an intermediate artifact and can be thought of as a
|
||||
"static Rust library". These `rlib` files, unlike `staticlib` files, are
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ em {
|
|||
|
||||
footer {
|
||||
border-top: 1px solid #ddd;
|
||||
font-size: 14.3px;
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
margin-top: 3em;
|
||||
|
|
@ -336,13 +336,11 @@ table th {
|
|||
|
||||
/* Code snippets */
|
||||
|
||||
.rusttest { display: none; }
|
||||
pre.rust { position: relative; }
|
||||
a.test-arrow {
|
||||
background-color: rgba(78, 139, 202, 0.2);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
|
||||
background-color: #4e8bca;
|
||||
color: #f5f5f5;
|
||||
padding: 5px 10px 5px 10px;
|
||||
border-radius: 5px;
|
||||
|
|
@ -350,6 +348,10 @@ a.test-arrow {
|
|||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
a.test-arrow:hover{
|
||||
background-color: #4e8bca;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.unstable-feature {
|
||||
border: 2px solid red;
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ def extract_length_and_ptr_from_slice(slice_val):
|
|||
UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
|
||||
|
||||
def extract_type_name(qualified_type_name):
|
||||
'''Extracts the type name from a fully qualified path'''
|
||||
"""Extracts the type name from a fully qualified path"""
|
||||
if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
|
||||
return qualified_type_name
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ def rust_pretty_printer_lookup_function(gdb_val):
|
|||
#=------------------------------------------------------------------------------
|
||||
# Pretty Printer Classes
|
||||
#=------------------------------------------------------------------------------
|
||||
class RustStructPrinter:
|
||||
class RustStructPrinter(object):
|
||||
def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
|
||||
self.__val = val
|
||||
self.__omit_first_field = omit_first_field
|
||||
|
|
@ -205,11 +205,12 @@ class RustStructPrinter:
|
|||
return ""
|
||||
|
||||
|
||||
class RustSlicePrinter:
|
||||
class RustSlicePrinter(object):
|
||||
def __init__(self, val):
|
||||
self.__val = val
|
||||
|
||||
def display_hint(self):
|
||||
@staticmethod
|
||||
def display_hint():
|
||||
return "array"
|
||||
|
||||
def to_string(self):
|
||||
|
|
@ -226,7 +227,7 @@ class RustSlicePrinter:
|
|||
yield (str(index), (raw_ptr + index).dereference())
|
||||
|
||||
|
||||
class RustStringSlicePrinter:
|
||||
class RustStringSlicePrinter(object):
|
||||
def __init__(self, val):
|
||||
self.__val = val
|
||||
|
||||
|
|
@ -236,11 +237,12 @@ class RustStringSlicePrinter:
|
|||
return '"%s"' % raw_ptr.string(encoding="utf-8", length=length)
|
||||
|
||||
|
||||
class RustStdVecPrinter:
|
||||
class RustStdVecPrinter(object):
|
||||
def __init__(self, val):
|
||||
self.__val = val
|
||||
|
||||
def display_hint(self):
|
||||
@staticmethod
|
||||
def display_hint():
|
||||
return "array"
|
||||
|
||||
def to_string(self):
|
||||
|
|
@ -255,7 +257,7 @@ class RustStdVecPrinter:
|
|||
yield (str(index), (gdb_ptr + index).dereference())
|
||||
|
||||
|
||||
class RustStdStringPrinter:
|
||||
class RustStdStringPrinter(object):
|
||||
def __init__(self, val):
|
||||
self.__val = val
|
||||
|
||||
|
|
@ -266,7 +268,7 @@ class RustStdStringPrinter:
|
|||
length=length)
|
||||
|
||||
|
||||
class RustCStyleVariantPrinter:
|
||||
class RustCStyleVariantPrinter(object):
|
||||
def __init__(self, val):
|
||||
assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
|
||||
self.__val = val
|
||||
|
|
@ -275,7 +277,7 @@ class RustCStyleVariantPrinter:
|
|||
return str(self.__val.get_wrapped_value())
|
||||
|
||||
|
||||
class IdentityPrinter:
|
||||
class IdentityPrinter(object):
|
||||
def __init__(self, string):
|
||||
self.string = string
|
||||
|
||||
|
|
|
|||
|
|
@ -37,14 +37,14 @@ DEBUG_OUTPUT = False
|
|||
|
||||
|
||||
def print_debug(s):
|
||||
"Print something if DEBUG_OUTPUT is True"
|
||||
"""Print something if DEBUG_OUTPUT is True"""
|
||||
global DEBUG_OUTPUT
|
||||
if DEBUG_OUTPUT:
|
||||
print("DEBUG: " + str(s))
|
||||
|
||||
|
||||
def normalize_whitespace(s):
|
||||
"Replace newlines, tabs, multiple spaces, etc with exactly one space"
|
||||
"""Replace newlines, tabs, multiple spaces, etc with exactly one space"""
|
||||
return re.sub("\s+", " ", s)
|
||||
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ registered_breakpoints = set()
|
|||
|
||||
|
||||
def execute_command(command_interpreter, command):
|
||||
"Executes a single CLI command"
|
||||
"""Executes a single CLI command"""
|
||||
global new_breakpoints
|
||||
global registered_breakpoints
|
||||
|
||||
|
|
|
|||
|
|
@ -171,10 +171,10 @@ def print_val(lldb_val, internal_dict):
|
|||
#=--------------------------------------------------------------------------------------------------
|
||||
|
||||
def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tuple_like):
|
||||
'''
|
||||
"""
|
||||
Prints a struct, tuple, or tuple struct value with Rust syntax.
|
||||
Ignores any fields before field_start_index.
|
||||
'''
|
||||
"""
|
||||
assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT
|
||||
|
||||
if omit_type_name:
|
||||
|
|
@ -221,7 +221,7 @@ def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tu
|
|||
"body": body}
|
||||
|
||||
def print_pointer_val(val, internal_dict):
|
||||
'''Prints a pointer value with Rust syntax'''
|
||||
"""Prints a pointer value with Rust syntax"""
|
||||
assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
|
||||
sigil = "&"
|
||||
type_name = val.type.get_unqualified_type_name()
|
||||
|
|
@ -275,8 +275,8 @@ def print_std_string_val(val, internal_dict):
|
|||
#=--------------------------------------------------------------------------------------------------
|
||||
|
||||
def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
|
||||
'''Prints a contigous memory range, interpreting it as values of the
|
||||
pointee-type of data_ptr_val.'''
|
||||
"""Prints a contigous memory range, interpreting it as values of the
|
||||
pointee-type of data_ptr_val."""
|
||||
|
||||
data_ptr_type = data_ptr_val.type
|
||||
assert data_ptr_type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ LIB_PREFIX=lib
|
|||
|
||||
OS=`uname -s`
|
||||
case $OS in
|
||||
("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD"|"SunOS")
|
||||
("Linux"|"FreeBSD"|"DragonFly"|"Bitrig"|"OpenBSD"|"SunOS"|"Haiku")
|
||||
BIN_SUF=
|
||||
LIB_SUF=.so
|
||||
;;
|
||||
|
|
@ -71,6 +71,7 @@ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}log*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR
|
|||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rbml*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}serialize*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}term*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}proc_macro*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
|
||||
|
||||
# do not fail if one of the above fails, as all we need is a working rustc!
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -119,16 +119,19 @@ class Void(Type):
|
|||
def __init__(self):
|
||||
Type.__init__(self, 0)
|
||||
|
||||
def compiler_ctor(self):
|
||||
@staticmethod
|
||||
def compiler_ctor():
|
||||
return '::VOID'
|
||||
|
||||
def compiler_ctor_ref(self):
|
||||
return '&' + self.compiler_ctor()
|
||||
|
||||
def rust_name(self):
|
||||
@staticmethod
|
||||
def rust_name():
|
||||
return '()'
|
||||
|
||||
def type_info(self, platform_info):
|
||||
@staticmethod
|
||||
def type_info(platform_info):
|
||||
return None
|
||||
|
||||
def __eq__(self, other):
|
||||
|
|
@ -282,7 +285,7 @@ class Vector(Type):
|
|||
|
||||
class Pointer(Type):
|
||||
def __init__(self, elem, llvm_elem, const):
|
||||
self._elem = elem;
|
||||
self._elem = elem
|
||||
self._llvm_elem = llvm_elem
|
||||
self._const = const
|
||||
Type.__init__(self, BITWIDTH_POINTER)
|
||||
|
|
@ -503,7 +506,7 @@ class GenericIntrinsic(object):
|
|||
# must be a power of two
|
||||
assert width & (width - 1) == 0
|
||||
def recur(processed, untouched):
|
||||
if untouched == []:
|
||||
if not untouched:
|
||||
ret = processed[0]
|
||||
args = processed[1:]
|
||||
yield MonomorphicIntrinsic(self._platform, self.intrinsic, width,
|
||||
|
|
@ -756,22 +759,26 @@ class ExternBlock(object):
|
|||
def __init__(self):
|
||||
pass
|
||||
|
||||
def open(self, platform):
|
||||
@staticmethod
|
||||
def open(platform):
|
||||
return 'extern "platform-intrinsic" {'
|
||||
|
||||
def render(self, mono):
|
||||
@staticmethod
|
||||
def render(mono):
|
||||
return ' fn {}{}{};'.format(mono.platform_prefix(),
|
||||
mono.intrinsic_name(),
|
||||
mono.intrinsic_signature())
|
||||
|
||||
def close(self):
|
||||
@staticmethod
|
||||
def close():
|
||||
return '}'
|
||||
|
||||
class CompilerDefs(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def open(self, platform):
|
||||
@staticmethod
|
||||
def open(platform):
|
||||
return '''\
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
|
|
@ -798,7 +805,8 @@ pub fn find(name: &str) -> Option<Intrinsic> {{
|
|||
if !name.starts_with("{0}") {{ return None }}
|
||||
Some(match &name["{0}".len()..] {{'''.format(platform.platform_prefix())
|
||||
|
||||
def render(self, mono):
|
||||
@staticmethod
|
||||
def render(mono):
|
||||
return '''\
|
||||
"{}" => Intrinsic {{
|
||||
inputs: {{ static INPUTS: [&'static Type; {}] = [{}]; &INPUTS }},
|
||||
|
|
@ -810,7 +818,8 @@ pub fn find(name: &str) -> Option<Intrinsic> {{
|
|||
mono.compiler_ret(),
|
||||
mono.llvm_name())
|
||||
|
||||
def close(self):
|
||||
@staticmethod
|
||||
def close():
|
||||
return '''\
|
||||
_ => return None,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ def run(test):
|
|||
|
||||
|
||||
def interact(proc, queue):
|
||||
line = ""
|
||||
n = 0
|
||||
while proc.poll() is None:
|
||||
line = proc.stdout.readline()
|
||||
|
|
@ -185,7 +184,6 @@ def interact(proc, queue):
|
|||
continue
|
||||
assert line.endswith('\n'), "incomplete line: " + repr(line)
|
||||
queue.put(line)
|
||||
line = ""
|
||||
n += 1
|
||||
if n % UPDATE_EVERY_N == 0:
|
||||
msg("got", str(n // 1000) + "k", "records")
|
||||
|
|
|
|||
|
|
@ -82,28 +82,28 @@ def load_unicode_data(f):
|
|||
canon_decomp = {}
|
||||
compat_decomp = {}
|
||||
|
||||
udict = {};
|
||||
range_start = -1;
|
||||
udict = {}
|
||||
range_start = -1
|
||||
for line in fileinput.input(f):
|
||||
data = line.split(';');
|
||||
data = line.split(';')
|
||||
if len(data) != 15:
|
||||
continue
|
||||
cp = int(data[0], 16);
|
||||
cp = int(data[0], 16)
|
||||
if is_surrogate(cp):
|
||||
continue
|
||||
if range_start >= 0:
|
||||
for i in xrange(range_start, cp):
|
||||
udict[i] = data;
|
||||
range_start = -1;
|
||||
udict[i] = data
|
||||
range_start = -1
|
||||
if data[1].endswith(", First>"):
|
||||
range_start = cp;
|
||||
continue;
|
||||
udict[cp] = data;
|
||||
range_start = cp
|
||||
continue
|
||||
udict[cp] = data
|
||||
|
||||
for code in udict:
|
||||
[code_org, name, gencat, combine, bidi,
|
||||
(code_org, name, gencat, combine, bidi,
|
||||
decomp, deci, digit, num, mirror,
|
||||
old, iso, upcase, lowcase, titlecase ] = udict[code];
|
||||
old, iso, upcase, lowcase, titlecase) = udict[code]
|
||||
|
||||
# generate char to char direct common and simple conversions
|
||||
# uppercase to lowercase
|
||||
|
|
@ -382,7 +382,7 @@ def emit_bool_trie(f, name, t_data, is_pub=True):
|
|||
global bytes_old, bytes_new
|
||||
bytes_old += 8 * len(t_data)
|
||||
CHUNK = 64
|
||||
rawdata = [False] * 0x110000;
|
||||
rawdata = [False] * 0x110000
|
||||
for (lo, hi) in t_data:
|
||||
for cp in range(lo, hi + 1):
|
||||
rawdata[cp] = True
|
||||
|
|
|
|||
|
|
@ -10,35 +10,11 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
//! Threadsafe reference-counted boxes (the `Arc<T>` type).
|
||||
//! Thread-safe reference-counting pointers.
|
||||
//!
|
||||
//! The `Arc<T>` type provides shared ownership of an immutable value through
|
||||
//! atomic reference counting.
|
||||
//! See the [`Arc<T>`][arc] documentation for more details.
|
||||
//!
|
||||
//! `Weak<T>` is a weak reference to the `Arc<T>` box, and it is created by
|
||||
//! the `downgrade` method.
|
||||
//! # Examples
|
||||
//!
|
||||
//! Sharing some immutable data between threads:
|
||||
//!
|
||||
// Note that we **do not** run these tests here. The windows builders get super
|
||||
// unhappy of a thread outlives the main thread and then exits at the same time
|
||||
// (something deadlocks) so we just avoid this entirely by not running these
|
||||
// tests.
|
||||
//! ```no_run
|
||||
//! use std::sync::Arc;
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! let five = Arc::new(5);
|
||||
//!
|
||||
//! for _ in 0..10 {
|
||||
//! let five = five.clone();
|
||||
//!
|
||||
//! thread::spawn(move || {
|
||||
//! println!("{:?}", five);
|
||||
//! });
|
||||
//! }
|
||||
//! ```
|
||||
//! [arc]: struct.Arc.html
|
||||
|
||||
use boxed::Box;
|
||||
|
||||
|
|
@ -62,72 +38,114 @@ use heap::deallocate;
|
|||
|
||||
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
||||
|
||||
/// An atomically reference counted wrapper for shared state.
|
||||
/// Destruction is deterministic, and will occur as soon as the last owner is
|
||||
/// gone. It is marked as `Send` because it uses atomic reference counting.
|
||||
/// A thread-safe reference-counting pointer.
|
||||
///
|
||||
/// If you do not need thread-safety, and just need shared ownership, consider
|
||||
/// the [`Rc<T>` type](../rc/struct.Rc.html). It is the same as `Arc<T>`, but
|
||||
/// does not use atomics, making it both thread-unsafe as well as significantly
|
||||
/// faster when updating the reference count.
|
||||
/// The type `Arc<T>` provides shared ownership of a value of type `T`,
|
||||
/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces
|
||||
/// a new pointer to the same value in the heap. When the last `Arc`
|
||||
/// pointer to a given value is destroyed, the pointed-to value is
|
||||
/// also destroyed.
|
||||
///
|
||||
/// Note: the inherent methods defined on `Arc<T>` are all associated functions,
|
||||
/// which means that you have to call them as e.g. `Arc::get_mut(&value)`
|
||||
/// instead of `value.get_mut()`. This is so that there are no conflicts with
|
||||
/// methods on the inner type `T`, which are what you want to call in the
|
||||
/// majority of cases.
|
||||
/// Shared references in Rust disallow mutation by default, and `Arc` is no
|
||||
/// exception. If you need to mutate through an `Arc`, use [`Mutex`][mutex],
|
||||
/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types.
|
||||
///
|
||||
/// # Examples
|
||||
/// `Arc` uses atomic operations for reference counting, so `Arc`s can be
|
||||
/// sent between threads. In other words, `Arc<T>` implements [`Send`][send]
|
||||
/// as long as `T` implements `Send` and [`Sync`][sync]. The disadvantage is
|
||||
/// that atomic operations are more expensive than ordinary memory accesses.
|
||||
/// If you are not sharing reference-counted values between threads, consider
|
||||
/// using [`rc::Rc`][rc] for lower overhead. `Rc` is a safe default, because
|
||||
/// the compiler will catch any attempt to send an `Rc` between threads.
|
||||
/// However, a library might choose `Arc` in order to give library consumers
|
||||
/// more flexibility.
|
||||
///
|
||||
/// In this example, a large vector of data will be shared by several threads. First we
|
||||
/// wrap it with a `Arc::new` and then clone the `Arc<T>` reference for every thread (which will
|
||||
/// increase the reference count atomically).
|
||||
/// The [`downgrade`][downgrade] method can be used to create a non-owning
|
||||
/// [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d
|
||||
/// to an `Arc`, but this will return [`None`][option] if the value has
|
||||
/// already been dropped.
|
||||
///
|
||||
/// A cycle between `Arc` pointers will never be deallocated. For this reason,
|
||||
/// `Weak` is used to break cycles. For example, a tree could have strong
|
||||
/// `Arc` pointers from parent nodes to children, and `Weak` pointers from
|
||||
/// children back to their parents.
|
||||
///
|
||||
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
|
||||
/// so you can call `T`'s methods on a value of type `Arc<T>`. To avoid name
|
||||
/// clashes with `T`'s methods, the methods of `Arc<T>` itself are [associated
|
||||
/// functions][assoc], called using function-like syntax:
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
/// use std::thread;
|
||||
/// let my_arc = Arc::new(());
|
||||
///
|
||||
/// fn main() {
|
||||
/// let numbers: Vec<_> = (0..100).collect();
|
||||
/// let shared_numbers = Arc::new(numbers);
|
||||
///
|
||||
/// for _ in 0..10 {
|
||||
/// // prepare a copy of reference here and it will be moved to the thread
|
||||
/// let child_numbers = shared_numbers.clone();
|
||||
///
|
||||
/// thread::spawn(move || {
|
||||
/// let local_numbers = &child_numbers[..];
|
||||
///
|
||||
/// // Work with the local numbers
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// Arc::downgrade(&my_arc);
|
||||
/// ```
|
||||
/// You can also share mutable data between threads safely
|
||||
/// by putting it inside `Mutex` and then share `Mutex` immutably
|
||||
/// with `Arc<T>` as shown below.
|
||||
///
|
||||
// See comment at the top of this file for why the test is no_run
|
||||
/// `Weak<T>` does not auto-dereference to `T`, because the value may have
|
||||
/// already been destroyed.
|
||||
///
|
||||
/// [arc]: struct.Arc.html
|
||||
/// [weak]: struct.Weak.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
|
||||
/// [mutex]: ../../std/sync/struct.Mutex.html
|
||||
/// [rwlock]: ../../std/sync/struct.RwLock.html
|
||||
/// [atomic]: ../../std/sync/atomic/index.html
|
||||
/// [send]: ../../std/marker/trait.Send.html
|
||||
/// [sync]: ../../std/marker/trait.Sync.html
|
||||
/// [deref]: ../../std/ops/trait.Deref.html
|
||||
/// [downgrade]: struct.Arc.html#method.downgrade
|
||||
/// [upgrade]: struct.Weak.html#method.upgrade
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
/// [assoc]: ../../book/method-syntax.html#associated-functions
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Sharing some immutable data between threads:
|
||||
///
|
||||
// Note that we **do not** run these tests here. The windows builders get super
|
||||
// unhappy if a thread outlives the main thread and then exits at the same time
|
||||
// (something deadlocks) so we just avoid this entirely by not running these
|
||||
// tests.
|
||||
/// ```no_run
|
||||
/// use std::sync::{Arc, Mutex};
|
||||
/// use std::sync::Arc;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// let five = Arc::new(Mutex::new(5));
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// for _ in 0..10 {
|
||||
/// let five = five.clone();
|
||||
///
|
||||
/// thread::spawn(move || {
|
||||
/// let mut number = five.lock().unwrap();
|
||||
///
|
||||
/// *number += 1;
|
||||
///
|
||||
/// println!("{}", *number); // prints 6
|
||||
/// println!("{:?}", five);
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
///
|
||||
/// Sharing a mutable `AtomicUsize`:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::sync::Arc;
|
||||
/// use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
/// use std::thread;
|
||||
///
|
||||
/// let val = Arc::new(AtomicUsize::new(5));
|
||||
///
|
||||
/// for _ in 0..10 {
|
||||
/// let val = val.clone();
|
||||
///
|
||||
/// thread::spawn(move || {
|
||||
/// let v = val.fetch_add(1, Ordering::SeqCst);
|
||||
/// println!("{:?}", v);
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// See the [`rc` documentation][rc_examples] for more examples of reference
|
||||
/// counting in general.
|
||||
///
|
||||
/// [rc_examples]: ../../std/rc/index.html#examples
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Arc<T: ?Sized> {
|
||||
ptr: Shared<ArcInner<T>>,
|
||||
|
|
@ -141,19 +159,18 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
|
|||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
|
||||
|
||||
/// A weak pointer to an `Arc`.
|
||||
/// A weak version of [`Arc`][arc].
|
||||
///
|
||||
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
|
||||
/// used to break cycles between `Arc` pointers.
|
||||
/// `Weak` pointers do not count towards determining if the inner value
|
||||
/// should be dropped.
|
||||
///
|
||||
/// A `Weak<T>` pointer can be upgraded to an `Arc<T>` pointer, but
|
||||
/// will return `None` if the value has already been dropped.
|
||||
/// The typical way to obtain a `Weak` pointer is to call
|
||||
/// [`Arc::downgrade`][downgrade].
|
||||
///
|
||||
/// For example, a tree with parent pointers can be represented by putting the
|
||||
/// nodes behind strong `Arc<T>` pointers, and then storing the parent pointers
|
||||
/// as `Weak<T>` pointers.
|
||||
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
/// See the [`Arc`][arc] documentation for more details.
|
||||
///
|
||||
/// [arc]: struct.Arc.html
|
||||
/// [downgrade]: struct.Arc.html#method.downgrade
|
||||
#[stable(feature = "arc_weak", since = "1.4.0")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
ptr: Shared<ArcInner<T>>,
|
||||
|
|
@ -211,12 +228,15 @@ impl<T> Arc<T> {
|
|||
Arc { ptr: unsafe { Shared::new(Box::into_raw(x)) } }
|
||||
}
|
||||
|
||||
/// Unwraps the contained value if the `Arc<T>` has exactly one strong reference.
|
||||
/// Returns the contained value, if the `Arc` has exactly one strong reference.
|
||||
///
|
||||
/// Otherwise, an `Err` is returned with the same `Arc<T>`.
|
||||
/// Otherwise, an [`Err`][result] is returned with the same `Arc` that was
|
||||
/// passed in.
|
||||
///
|
||||
/// This will succeed even if there are outstanding weak references.
|
||||
///
|
||||
/// [result]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -227,7 +247,7 @@ impl<T> Arc<T> {
|
|||
///
|
||||
/// let x = Arc::new(4);
|
||||
/// let _y = x.clone();
|
||||
/// assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4)));
|
||||
/// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "arc_unique", since = "1.4.0")]
|
||||
|
|
@ -253,7 +273,9 @@ impl<T> Arc<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Downgrades the `Arc<T>` to a `Weak<T>` reference.
|
||||
/// Creates a new [`Weak`][weak] pointer to this value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -291,7 +313,27 @@ impl<T: ?Sized> Arc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
/// Gets the number of [`Weak`][weak] pointers to this value.
|
||||
///
|
||||
/// Be careful how you use this information, because another thread
|
||||
/// may change the weak count at any time.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(arc_counts)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5);
|
||||
/// let _weak_five = Arc::downgrade(&five);
|
||||
///
|
||||
/// // This assertion is deterministic because we haven't shared
|
||||
/// // the `Arc` or `Weak` between threads.
|
||||
/// assert_eq!(1, Arc::weak_count(&five));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "arc_counts", reason = "not clearly useful, and racy",
|
||||
issue = "28356")]
|
||||
|
|
@ -299,7 +341,25 @@ impl<T: ?Sized> Arc<T> {
|
|||
this.inner().weak.load(SeqCst) - 1
|
||||
}
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
/// Gets the number of strong (`Arc`) pointers to this value.
|
||||
///
|
||||
/// Be careful how you use this information, because another thread
|
||||
/// may change the strong count at any time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(arc_counts)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5);
|
||||
/// let _also_five = five.clone();
|
||||
///
|
||||
/// // This assertion is deterministic because we haven't shared
|
||||
/// // the `Arc` between threads.
|
||||
/// assert_eq!(2, Arc::strong_count(&five));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "arc_counts", reason = "not clearly useful, and racy",
|
||||
issue = "28356")]
|
||||
|
|
@ -336,8 +396,8 @@ impl<T: ?Sized> Arc<T> {
|
|||
#[unstable(feature = "ptr_eq",
|
||||
reason = "newly added",
|
||||
issue = "36497")]
|
||||
/// Return whether two `Arc` references point to the same value
|
||||
/// (not just values that compare equal).
|
||||
/// Returns true if the two `Arc`s point to the same value (not
|
||||
/// just values that compare as equal).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -362,9 +422,10 @@ impl<T: ?Sized> Arc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for Arc<T> {
|
||||
/// Makes a clone of the `Arc<T>`.
|
||||
/// Makes a clone of the `Arc` pointer.
|
||||
///
|
||||
/// This increases the strong reference count.
|
||||
/// This creates another pointer to the same inner value, increasing the
|
||||
/// strong reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -420,11 +481,17 @@ impl<T: ?Sized> Deref for Arc<T> {
|
|||
}
|
||||
|
||||
impl<T: Clone> Arc<T> {
|
||||
/// Make a mutable reference into the given `Arc<T>`.
|
||||
/// If the `Arc<T>` has more than one strong reference, or any weak
|
||||
/// references, the inner data is cloned.
|
||||
/// Makes a mutable reference into the given `Arc`.
|
||||
///
|
||||
/// This is also referred to as a copy-on-write.
|
||||
/// If there are other `Arc` or [`Weak`][weak] pointers to the same value,
|
||||
/// then `make_mut` will invoke [`clone`][clone] on the inner value to
|
||||
/// ensure unique ownership. This is also referred to as clone-on-write.
|
||||
///
|
||||
/// See also [`get_mut`][get_mut], which will fail rather than cloning.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
|
||||
/// [get_mut]: struct.Arc.html#method.get_mut
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -439,10 +506,9 @@ impl<T: Clone> Arc<T> {
|
|||
/// *Arc::make_mut(&mut data) += 1; // Won't clone anything
|
||||
/// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything
|
||||
///
|
||||
/// // Note: data and other_data now point to different numbers
|
||||
/// // Now `data` and `other_data` point to different values.
|
||||
/// assert_eq!(*data, 8);
|
||||
/// assert_eq!(*other_data, 12);
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "arc_unique", since = "1.4.0")]
|
||||
|
|
@ -501,8 +567,19 @@ impl<T: Clone> Arc<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized> Arc<T> {
|
||||
/// Returns a mutable reference to the contained value if the `Arc<T>` has
|
||||
/// one strong reference and no weak references.
|
||||
/// Returns a mutable reference to the inner value, if there are
|
||||
/// no other `Arc` or [`Weak`][weak] pointers to the same value.
|
||||
///
|
||||
/// Returns [`None`][option] otherwise, because it is not safe to
|
||||
/// mutate a shared value.
|
||||
///
|
||||
/// See also [`make_mut`][make_mut], which will [`clone`][clone]
|
||||
/// the inner value when it's shared.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
/// [make_mut]: struct.Arc.html#method.make_mut
|
||||
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -564,30 +641,32 @@ impl<T: ?Sized> Arc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Arc<T> {
|
||||
/// Drops the `Arc<T>`.
|
||||
/// Drops the `Arc`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
/// count becomes zero and the only other references are `Weak<T>` ones,
|
||||
/// `drop`s the inner value.
|
||||
/// count reaches zero then the only other references (if any) are
|
||||
/// [`Weak`][weak], so we `drop` the inner value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Arc::new(5);
|
||||
/// struct Foo;
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(five); // explicit drop
|
||||
/// impl Drop for Foo {
|
||||
/// fn drop(&mut self) {
|
||||
/// println!("dropped!");
|
||||
/// }
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// // stuff
|
||||
/// let foo = Arc::new(Foo);
|
||||
/// let foo2 = foo.clone();
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// drop(foo); // Doesn't print anything
|
||||
/// drop(foo2); // Prints "dropped!"
|
||||
/// ```
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
#[inline]
|
||||
|
|
@ -625,10 +704,14 @@ impl<T: ?Sized> Drop for Arc<T> {
|
|||
}
|
||||
|
||||
impl<T> Weak<T> {
|
||||
/// Constructs a new `Weak<T>` without an accompanying instance of T.
|
||||
/// Constructs a new `Weak<T>`, without an accompanying instance of `T`.
|
||||
///
|
||||
/// This allocates memory for T, but does not initialize it. Calling
|
||||
/// Weak<T>::upgrade() on the return value always gives None.
|
||||
/// This allocates memory for `T`, but does not initialize it. Calling
|
||||
/// [`upgrade`][upgrade] on the return value always gives
|
||||
/// [`None`][option].
|
||||
///
|
||||
/// [upgrade]: struct.Weak.html#method.upgrade
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -636,6 +719,7 @@ impl<T> Weak<T> {
|
|||
/// use std::sync::Weak;
|
||||
///
|
||||
/// let empty: Weak<i64> = Weak::new();
|
||||
/// assert!(empty.upgrade().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
pub fn new() -> Weak<T> {
|
||||
|
|
@ -652,12 +736,13 @@ impl<T> Weak<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
/// Upgrades the `Weak` pointer to an [`Arc`][arc], if possible.
|
||||
///
|
||||
/// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
|
||||
/// Returns [`None`][option] if the strong count has reached zero and the
|
||||
/// inner value was destroyed.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was
|
||||
/// destroyed.
|
||||
/// [arc]: struct.Arc.html
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -669,6 +754,13 @@ impl<T: ?Sized> Weak<T> {
|
|||
/// let weak_five = Arc::downgrade(&five);
|
||||
///
|
||||
/// let strong_five: Option<Arc<_>> = weak_five.upgrade();
|
||||
/// assert!(strong_five.is_some());
|
||||
///
|
||||
/// // Destroy all strong pointers.
|
||||
/// drop(strong_five);
|
||||
/// drop(five);
|
||||
///
|
||||
/// assert!(weak_five.upgrade().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "arc_weak", since = "1.4.0")]
|
||||
pub fn upgrade(&self) -> Option<Arc<T>> {
|
||||
|
|
@ -711,9 +803,10 @@ impl<T: ?Sized> Weak<T> {
|
|||
|
||||
#[stable(feature = "arc_weak", since = "1.4.0")]
|
||||
impl<T: ?Sized> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
/// Makes a clone of the `Weak` pointer.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
/// This creates another pointer to the same inner value, increasing the
|
||||
/// weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -745,7 +838,23 @@ impl<T: ?Sized> Clone for Weak<T> {
|
|||
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
impl<T> Default for Weak<T> {
|
||||
/// Constructs a new `Weak<T>` without an accompanying instance of T.
|
||||
/// Constructs a new `Weak<T>`, without an accompanying instance of `T`.
|
||||
///
|
||||
/// This allocates memory for `T`, but does not initialize it. Calling
|
||||
/// [`upgrade`][upgrade] on the return value always gives
|
||||
/// [`None`][option].
|
||||
///
|
||||
/// [upgrade]: struct.Weak.html#method.upgrade
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Weak;
|
||||
///
|
||||
/// let empty: Weak<i64> = Default::default();
|
||||
/// assert!(empty.upgrade().is_none());
|
||||
/// ```
|
||||
fn default() -> Weak<T> {
|
||||
Weak::new()
|
||||
}
|
||||
|
|
@ -753,7 +862,7 @@ impl<T> Default for Weak<T> {
|
|||
|
||||
#[stable(feature = "arc_weak", since = "1.4.0")]
|
||||
impl<T: ?Sized> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
/// Drops the `Weak` pointer.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
///
|
||||
|
|
@ -762,21 +871,22 @@ impl<T: ?Sized> Drop for Weak<T> {
|
|||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Arc::new(5);
|
||||
/// let weak_five = Arc::downgrade(&five);
|
||||
/// struct Foo;
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(weak_five); // explicit drop
|
||||
/// impl Drop for Foo {
|
||||
/// fn drop(&mut self) {
|
||||
/// println!("dropped!");
|
||||
/// }
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Arc::new(5);
|
||||
/// let weak_five = Arc::downgrade(&five);
|
||||
///
|
||||
/// // stuff
|
||||
/// let foo = Arc::new(Foo);
|
||||
/// let weak_foo = Arc::downgrade(&foo);
|
||||
/// let other_weak_foo = weak_foo.clone();
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// drop(weak_foo); // Doesn't print anything
|
||||
/// drop(foo); // Prints "dropped!"
|
||||
///
|
||||
/// assert!(other_weak_foo.upgrade().is_none());
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
let ptr = *self.ptr;
|
||||
|
|
@ -798,9 +908,9 @@ impl<T: ?Sized> Drop for Weak<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
|
||||
/// Equality for two `Arc<T>`s.
|
||||
/// Equality for two `Arc`s.
|
||||
///
|
||||
/// Two `Arc<T>`s are equal if their inner value are equal.
|
||||
/// Two `Arc`s are equal if their inner values are equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -809,15 +919,15 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
|
|||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five == Arc::new(5);
|
||||
/// assert!(five == Arc::new(5));
|
||||
/// ```
|
||||
fn eq(&self, other: &Arc<T>) -> bool {
|
||||
*(*self) == *(*other)
|
||||
}
|
||||
|
||||
/// Inequality for two `Arc<T>`s.
|
||||
/// Inequality for two `Arc`s.
|
||||
///
|
||||
/// Two `Arc<T>`s are unequal if their inner value are unequal.
|
||||
/// Two `Arc`s are unequal if their inner values are unequal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -826,7 +936,7 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
|
|||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five != Arc::new(5);
|
||||
/// assert!(five != Arc::new(6));
|
||||
/// ```
|
||||
fn ne(&self, other: &Arc<T>) -> bool {
|
||||
*(*self) != *(*other)
|
||||
|
|
@ -834,7 +944,7 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
|
|||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
||||
/// Partial comparison for two `Arc<T>`s.
|
||||
/// Partial comparison for two `Arc`s.
|
||||
///
|
||||
/// The two are compared by calling `partial_cmp()` on their inner values.
|
||||
///
|
||||
|
|
@ -842,16 +952,17 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five.partial_cmp(&Arc::new(5));
|
||||
/// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6)));
|
||||
/// ```
|
||||
fn partial_cmp(&self, other: &Arc<T>) -> Option<Ordering> {
|
||||
(**self).partial_cmp(&**other)
|
||||
}
|
||||
|
||||
/// Less-than comparison for two `Arc<T>`s.
|
||||
/// Less-than comparison for two `Arc`s.
|
||||
///
|
||||
/// The two are compared by calling `<` on their inner values.
|
||||
///
|
||||
|
|
@ -862,13 +973,13 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
|||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five < Arc::new(5);
|
||||
/// assert!(five < Arc::new(6));
|
||||
/// ```
|
||||
fn lt(&self, other: &Arc<T>) -> bool {
|
||||
*(*self) < *(*other)
|
||||
}
|
||||
|
||||
/// 'Less-than or equal to' comparison for two `Arc<T>`s.
|
||||
/// 'Less than or equal to' comparison for two `Arc`s.
|
||||
///
|
||||
/// The two are compared by calling `<=` on their inner values.
|
||||
///
|
||||
|
|
@ -879,13 +990,13 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
|||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five <= Arc::new(5);
|
||||
/// assert!(five <= Arc::new(5));
|
||||
/// ```
|
||||
fn le(&self, other: &Arc<T>) -> bool {
|
||||
*(*self) <= *(*other)
|
||||
}
|
||||
|
||||
/// Greater-than comparison for two `Arc<T>`s.
|
||||
/// Greater-than comparison for two `Arc`s.
|
||||
///
|
||||
/// The two are compared by calling `>` on their inner values.
|
||||
///
|
||||
|
|
@ -896,13 +1007,13 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
|||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five > Arc::new(5);
|
||||
/// assert!(five > Arc::new(4));
|
||||
/// ```
|
||||
fn gt(&self, other: &Arc<T>) -> bool {
|
||||
*(*self) > *(*other)
|
||||
}
|
||||
|
||||
/// 'Greater-than or equal to' comparison for two `Arc<T>`s.
|
||||
/// 'Greater than or equal to' comparison for two `Arc`s.
|
||||
///
|
||||
/// The two are compared by calling `>=` on their inner values.
|
||||
///
|
||||
|
|
@ -913,7 +1024,7 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
|||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// five >= Arc::new(5);
|
||||
/// assert!(five >= Arc::new(5));
|
||||
/// ```
|
||||
fn ge(&self, other: &Arc<T>) -> bool {
|
||||
*(*self) >= *(*other)
|
||||
|
|
@ -921,6 +1032,20 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
|
|||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Ord> Ord for Arc<T> {
|
||||
/// Comparison for two `Arc`s.
|
||||
///
|
||||
/// The two are compared by calling `cmp()` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let five = Arc::new(5);
|
||||
///
|
||||
/// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6)));
|
||||
/// ```
|
||||
fn cmp(&self, other: &Arc<T>) -> Ordering {
|
||||
(**self).cmp(&**other)
|
||||
}
|
||||
|
|
@ -951,7 +1076,16 @@ impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Arc<T> {
|
||||
/// Creates a new `Arc<T>`, with the `Default` value for T.
|
||||
/// Creates a new `Arc<T>`, with the `Default` value for `T`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let x: Arc<i32> = Default::default();
|
||||
/// assert_eq!(*x, 0);
|
||||
/// ```
|
||||
fn default() -> Arc<T> {
|
||||
Arc::new(Default::default())
|
||||
}
|
||||
|
|
@ -1002,6 +1136,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn manually_share_arc() {
|
||||
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let arc_v = Arc::new(v);
|
||||
|
|
|
|||
|
|
@ -244,12 +244,14 @@ impl<T: ?Sized> Box<T> {
|
|||
/// the destructor of `T` and free the allocated memory. Since the
|
||||
/// way `Box` allocates and releases memory is unspecified, the
|
||||
/// only valid pointer to pass to this function is the one taken
|
||||
/// from another `Box` via the `Box::into_raw` function.
|
||||
/// from another `Box` via the [`Box::into_raw`] function.
|
||||
///
|
||||
/// This function is unsafe because improper use may lead to
|
||||
/// memory problems. For example, a double-free may occur if the
|
||||
/// function is called twice on the same raw pointer.
|
||||
///
|
||||
/// [`Box::into_raw`]: struct.Box.html#method.into_raw
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -269,12 +271,14 @@ impl<T: ?Sized> Box<T> {
|
|||
/// memory previously managed by the `Box`. In particular, the
|
||||
/// caller should properly destroy `T` and release the memory. The
|
||||
/// proper way to do so is to convert the raw pointer back into a
|
||||
/// `Box` with the `Box::from_raw` function.
|
||||
/// `Box` with the [`Box::from_raw`] function.
|
||||
///
|
||||
/// Note: this is an associated function, which means that you have
|
||||
/// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This
|
||||
/// is so that there is no conflict with a method on the inner type.
|
||||
///
|
||||
/// [`Box::from_raw`]: struct.Box.html#method.from_raw
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unique)]
|
||||
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
|
||||
#![feature(unsize)]
|
||||
|
||||
#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ use core::cmp;
|
|||
/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
|
||||
/// field. This allows zero-sized types to not be special-cased by consumers of
|
||||
/// this type.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
pub struct RawVec<T> {
|
||||
ptr: Unique<T>,
|
||||
cap: usize,
|
||||
|
|
@ -58,11 +57,7 @@ impl<T> RawVec<T> {
|
|||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
// !0 is usize::MAX. This branch should be stripped at compile time.
|
||||
let cap = if mem::size_of::<T>() == 0 {
|
||||
!0
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
|
||||
|
||||
// heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
|
||||
RawVec {
|
||||
|
|
@ -210,11 +205,7 @@ impl<T> RawVec<T> {
|
|||
|
||||
let (new_cap, ptr) = if self.cap == 0 {
|
||||
// skip to 4 because tiny Vec's are dumb; but not if that would cause overflow
|
||||
let new_cap = if elem_size > (!0) / 8 {
|
||||
1
|
||||
} else {
|
||||
4
|
||||
};
|
||||
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
|
||||
let ptr = heap::allocate(new_cap * elem_size, align);
|
||||
(new_cap, ptr)
|
||||
} else {
|
||||
|
|
@ -348,7 +339,7 @@ impl<T> RawVec<T> {
|
|||
let elem_size = mem::size_of::<T>();
|
||||
// Nothing we can really do about these checks :(
|
||||
let required_cap = used_cap.checked_add(needed_extra_cap)
|
||||
.expect("capacity overflow");
|
||||
.expect("capacity overflow");
|
||||
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
|
||||
let double_cap = self.cap * 2;
|
||||
// `double_cap` guarantees exponential growth.
|
||||
|
|
|
|||
|
|
@ -10,90 +10,139 @@
|
|||
|
||||
#![allow(deprecated)]
|
||||
|
||||
//! Unsynchronized reference-counted boxes (the `Rc<T>` type) which are usable
|
||||
//! only within a single thread.
|
||||
//! Single-threaded reference-counting pointers.
|
||||
//!
|
||||
//! The `Rc<T>` type provides shared ownership of an immutable value.
|
||||
//! Destruction is deterministic, and will occur as soon as the last owner is
|
||||
//! gone. It is marked as non-sendable because it avoids the overhead of atomic
|
||||
//! reference counting.
|
||||
//! The type [`Rc<T>`][rc] provides shared ownership of a value of type `T`,
|
||||
//! allocated in the heap. Invoking [`clone`][clone] on `Rc` produces a new
|
||||
//! pointer to the same value in the heap. When the last `Rc` pointer to a
|
||||
//! given value is destroyed, the pointed-to value is also destroyed.
|
||||
//!
|
||||
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer
|
||||
//! to the box. A `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but
|
||||
//! will return `None` if the value has already been dropped.
|
||||
//! Shared references in Rust disallow mutation by default, and `Rc` is no
|
||||
//! exception. If you need to mutate through an `Rc`, use [`Cell`][cell] or
|
||||
//! [`RefCell`][refcell].
|
||||
//!
|
||||
//! For example, a tree with parent pointers can be represented by putting the
|
||||
//! nodes behind strong `Rc<T>` pointers, and then storing the parent pointers
|
||||
//! as `Weak<T>` pointers.
|
||||
//! `Rc` uses non-atomic reference counting. This means that overhead is very
|
||||
//! low, but an `Rc` cannot be sent between threads, and consequently `Rc`
|
||||
//! does not implement [`Send`][send]. As a result, the Rust compiler
|
||||
//! will check *at compile time* that you are not sending `Rc`s between
|
||||
//! threads. If you need multi-threaded, atomic reference counting, use
|
||||
//! [`sync::Arc`][arc].
|
||||
//!
|
||||
//! The [`downgrade`][downgrade] method can be used to create a non-owning
|
||||
//! [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d
|
||||
//! to an `Rc`, but this will return [`None`][option] if the value has
|
||||
//! already been dropped.
|
||||
//!
|
||||
//! A cycle between `Rc` pointers will never be deallocated. For this reason,
|
||||
//! `Weak` is used to break cycles. For example, a tree could have strong
|
||||
//! `Rc` pointers from parent nodes to children, and `Weak` pointers from
|
||||
//! children back to their parents.
|
||||
//!
|
||||
//! `Rc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
|
||||
//! so you can call `T`'s methods on a value of type `Rc<T>`. To avoid name
|
||||
//! clashes with `T`'s methods, the methods of `Rc<T>` itself are [associated
|
||||
//! functions][assoc], called using function-like syntax:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::rc::Rc;
|
||||
//! let my_rc = Rc::new(());
|
||||
//!
|
||||
//! Rc::downgrade(&my_rc);
|
||||
//! ```
|
||||
//!
|
||||
//! `Weak<T>` does not auto-dereference to `T`, because the value may have
|
||||
//! already been destroyed.
|
||||
//!
|
||||
//! [rc]: struct.Rc.html
|
||||
//! [weak]: struct.Weak.html
|
||||
//! [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
|
||||
//! [cell]: ../../std/cell/struct.Cell.html
|
||||
//! [refcell]: ../../std/cell/struct.RefCell.html
|
||||
//! [send]: ../../std/marker/trait.Send.html
|
||||
//! [arc]: ../../std/sync/struct.Arc.html
|
||||
//! [deref]: ../../std/ops/trait.Deref.html
|
||||
//! [downgrade]: struct.Rc.html#method.downgrade
|
||||
//! [upgrade]: struct.Weak.html#method.upgrade
|
||||
//! [option]: ../../std/option/enum.Option.html
|
||||
//! [assoc]: ../../book/method-syntax.html#associated-functions
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`.
|
||||
//! We want to have our `Gadget`s point to their `Owner`. We can't do this with
|
||||
//! unique ownership, because more than one gadget may belong to the same
|
||||
//! `Owner`. `Rc<T>` allows us to share an `Owner` between multiple `Gadget`s,
|
||||
//! `Owner`. `Rc` allows us to share an `Owner` between multiple `Gadget`s,
|
||||
//! and have the `Owner` remain allocated as long as any `Gadget` points at it.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```
|
||||
//! use std::rc::Rc;
|
||||
//!
|
||||
//! struct Owner {
|
||||
//! name: String
|
||||
//! name: String,
|
||||
//! // ...other fields
|
||||
//! }
|
||||
//!
|
||||
//! struct Gadget {
|
||||
//! id: i32,
|
||||
//! owner: Rc<Owner>
|
||||
//! owner: Rc<Owner>,
|
||||
//! // ...other fields
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! // Create a reference counted Owner.
|
||||
//! let gadget_owner : Rc<Owner> = Rc::new(
|
||||
//! Owner { name: String::from("Gadget Man") }
|
||||
//! // Create a reference-counted `Owner`.
|
||||
//! let gadget_owner: Rc<Owner> = Rc::new(
|
||||
//! Owner {
|
||||
//! name: "Gadget Man".to_string(),
|
||||
//! }
|
||||
//! );
|
||||
//!
|
||||
//! // Create Gadgets belonging to gadget_owner. To increment the reference
|
||||
//! // count we clone the `Rc<T>` object.
|
||||
//! let gadget1 = Gadget { id: 1, owner: gadget_owner.clone() };
|
||||
//! let gadget2 = Gadget { id: 2, owner: gadget_owner.clone() };
|
||||
//! // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc<Owner>`
|
||||
//! // value gives us a new pointer to the same `Owner` value, incrementing
|
||||
//! // the reference count in the process.
|
||||
//! let gadget1 = Gadget {
|
||||
//! id: 1,
|
||||
//! owner: gadget_owner.clone(),
|
||||
//! };
|
||||
//! let gadget2 = Gadget {
|
||||
//! id: 2,
|
||||
//! owner: gadget_owner.clone(),
|
||||
//! };
|
||||
//!
|
||||
//! // Dispose of our local variable `gadget_owner`.
|
||||
//! drop(gadget_owner);
|
||||
//!
|
||||
//! // Despite dropping gadget_owner, we're still able to print out the name
|
||||
//! // of the Owner of the Gadgets. This is because we've only dropped the
|
||||
//! // reference count object, not the Owner it wraps. As long as there are
|
||||
//! // other `Rc<T>` objects pointing at the same Owner, it will remain
|
||||
//! // allocated. Notice that the `Rc<T>` wrapper around Gadget.owner gets
|
||||
//! // automatically dereferenced for us.
|
||||
//! // Despite dropping `gadget_owner`, we're still able to print out the name
|
||||
//! // of the `Owner` of the `Gadget`s. This is because we've only dropped a
|
||||
//! // single `Rc<Owner>`, not the `Owner` it points to. As long as there are
|
||||
//! // other `Rc<Owner>` values pointing at the same `Owner`, it will remain
|
||||
//! // allocated. The field projection `gadget1.owner.name` works because
|
||||
//! // `Rc<Owner>` automatically dereferences to `Owner`.
|
||||
//! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
|
||||
//! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);
|
||||
//!
|
||||
//! // At the end of the method, gadget1 and gadget2 get destroyed, and with
|
||||
//! // them the last counted references to our Owner. Gadget Man now gets
|
||||
//! // destroyed as well.
|
||||
//! // At the end of the function, `gadget1` and `gadget2` are destroyed, and
|
||||
//! // with them the last counted references to our `Owner`. Gadget Man now
|
||||
//! // gets destroyed as well.
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! If our requirements change, and we also need to be able to traverse from
|
||||
//! Owner → Gadget, we will run into problems: an `Rc<T>` pointer from Owner
|
||||
//! → Gadget introduces a cycle between the objects. This means that their
|
||||
//! reference counts can never reach 0, and the objects will remain allocated: a
|
||||
//! memory leak. In order to get around this, we can use `Weak<T>` pointers.
|
||||
//! These pointers don't contribute to the total count.
|
||||
//! `Owner` to `Gadget`, we will run into problems. An `Rc` pointer from `Owner`
|
||||
//! to `Gadget` introduces a cycle between the values. This means that their
|
||||
//! reference counts can never reach 0, and the values will remain allocated
|
||||
//! forever: a memory leak. In order to get around this, we can use `Weak`
|
||||
//! pointers.
|
||||
//!
|
||||
//! Rust actually makes it somewhat difficult to produce this loop in the first
|
||||
//! place: in order to end up with two objects that point at each other, one of
|
||||
//! them needs to be mutable. This is problematic because `Rc<T>` enforces
|
||||
//! memory safety by only giving out shared references to the object it wraps,
|
||||
//! place. In order to end up with two values that point at each other, one of
|
||||
//! them needs to be mutable. This is difficult because `Rc` enforces
|
||||
//! memory safety by only giving out shared references to the value it wraps,
|
||||
//! and these don't allow direct mutation. We need to wrap the part of the
|
||||
//! object we wish to mutate in a `RefCell`, which provides *interior
|
||||
//! value we wish to mutate in a [`RefCell`][refcell], which provides *interior
|
||||
//! mutability*: a method to achieve mutability through a shared reference.
|
||||
//! `RefCell` enforces Rust's borrowing rules at runtime. Read the `Cell`
|
||||
//! documentation for more details on interior mutability.
|
||||
//! `RefCell` enforces Rust's borrowing rules at runtime.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```
|
||||
//! use std::rc::Rc;
|
||||
//! use std::rc::Weak;
|
||||
//! use std::cell::RefCell;
|
||||
|
|
@ -111,41 +160,58 @@
|
|||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! // Create a reference counted Owner. Note the fact that we've put the
|
||||
//! // Owner's vector of Gadgets inside a RefCell so that we can mutate it
|
||||
//! // through a shared reference.
|
||||
//! let gadget_owner : Rc<Owner> = Rc::new(
|
||||
//! // Create a reference-counted `Owner`. Note that we've put the `Owner`'s
|
||||
//! // vector of `Gadget`s inside a `RefCell` so that we can mutate it through
|
||||
//! // a shared reference.
|
||||
//! let gadget_owner: Rc<Owner> = Rc::new(
|
||||
//! Owner {
|
||||
//! name: "Gadget Man".to_string(),
|
||||
//! gadgets: RefCell::new(Vec::new()),
|
||||
//! gadgets: RefCell::new(vec![]),
|
||||
//! }
|
||||
//! );
|
||||
//!
|
||||
//! // Create Gadgets belonging to gadget_owner as before.
|
||||
//! let gadget1 = Rc::new(Gadget{id: 1, owner: gadget_owner.clone()});
|
||||
//! let gadget2 = Rc::new(Gadget{id: 2, owner: gadget_owner.clone()});
|
||||
//! // Create `Gadget`s belonging to `gadget_owner`, as before.
|
||||
//! let gadget1 = Rc::new(
|
||||
//! Gadget {
|
||||
//! id: 1,
|
||||
//! owner: gadget_owner.clone(),
|
||||
//! }
|
||||
//! );
|
||||
//! let gadget2 = Rc::new(
|
||||
//! Gadget {
|
||||
//! id: 2,
|
||||
//! owner: gadget_owner.clone(),
|
||||
//! }
|
||||
//! );
|
||||
//!
|
||||
//! // Add the Gadgets to their Owner. To do this we mutably borrow from
|
||||
//! // the RefCell holding the Owner's Gadgets.
|
||||
//! gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget1));
|
||||
//! gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget2));
|
||||
//! // Add the `Gadget`s to their `Owner`.
|
||||
//! {
|
||||
//! let mut gadgets = gadget_owner.gadgets.borrow_mut();
|
||||
//! gadgets.push(Rc::downgrade(&gadget1));
|
||||
//! gadgets.push(Rc::downgrade(&gadget2));
|
||||
//!
|
||||
//! // Iterate over our Gadgets, printing their details out
|
||||
//! for gadget_opt in gadget_owner.gadgets.borrow().iter() {
|
||||
//! // `RefCell` dynamic borrow ends here.
|
||||
//! }
|
||||
//!
|
||||
//! // gadget_opt is a Weak<Gadget>. Since weak pointers can't guarantee
|
||||
//! // that their object is still allocated, we need to call upgrade()
|
||||
//! // on them to turn them into a strong reference. This returns an
|
||||
//! // Option, which contains a reference to our object if it still
|
||||
//! // exists.
|
||||
//! let gadget = gadget_opt.upgrade().unwrap();
|
||||
//! // Iterate over our `Gadget`s, printing their details out.
|
||||
//! for gadget_weak in gadget_owner.gadgets.borrow().iter() {
|
||||
//!
|
||||
//! // `gadget_weak` is a `Weak<Gadget>`. Since `Weak` pointers can't
|
||||
//! // guarantee the value is still allocated, we need to call
|
||||
//! // `upgrade`, which returns an `Option<Rc<Gadget>>`.
|
||||
//! //
|
||||
//! // In this case we know the value still exists, so we simply
|
||||
//! // `unwrap` the `Option`. In a more complicated program, you might
|
||||
//! // need graceful error handling for a `None` result.
|
||||
//!
|
||||
//! let gadget = gadget_weak.upgrade().unwrap();
|
||||
//! println!("Gadget {} owned by {}", gadget.id, gadget.owner.name);
|
||||
//! }
|
||||
//!
|
||||
//! // At the end of the method, gadget_owner, gadget1 and gadget2 get
|
||||
//! // destroyed. There are now no strong (`Rc<T>`) references to the gadgets.
|
||||
//! // Once they get destroyed, the Gadgets get destroyed. This zeroes the
|
||||
//! // reference count on Gadget Man, they get destroyed as well.
|
||||
//! // At the end of the function, `gadget_owner`, `gadget1`, and `gadget2`
|
||||
//! // are destroyed. There are now no strong (`Rc`) pointers to the
|
||||
//! // gadgets, so they are destroyed. This zeroes the reference count on
|
||||
//! // Gadget Man, so he gets destroyed as well.
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
|
|
@ -164,13 +230,14 @@ use core::hash::{Hash, Hasher};
|
|||
use core::intrinsics::{abort, assume};
|
||||
use core::marker;
|
||||
use core::marker::Unsize;
|
||||
use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
|
||||
use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
|
||||
use core::ops::Deref;
|
||||
use core::ops::CoerceUnsized;
|
||||
use core::ptr::{self, Shared};
|
||||
use core::convert::From;
|
||||
|
||||
use heap::deallocate;
|
||||
use raw_vec::RawVec;
|
||||
|
||||
struct RcBox<T: ?Sized> {
|
||||
strong: Cell<usize>,
|
||||
|
|
@ -179,16 +246,14 @@ struct RcBox<T: ?Sized> {
|
|||
}
|
||||
|
||||
|
||||
/// A reference-counted pointer type over an immutable value.
|
||||
/// A single-threaded reference-counting pointer.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more details.
|
||||
/// See the [module-level documentation](./index.html) for more details.
|
||||
///
|
||||
/// Note: the inherent methods defined on `Rc<T>` are all associated functions,
|
||||
/// which means that you have to call them as e.g. `Rc::get_mut(&value)` instead
|
||||
/// of `value.get_mut()`. This is so that there are no conflicts with methods
|
||||
/// on the inner type `T`, which are what you want to call in the majority of
|
||||
/// cases.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
/// The inherent methods of `Rc` are all associated functions, which means
|
||||
/// that you have to call them as e.g. `Rc::get_mut(&value)` instead of
|
||||
/// `value.get_mut()`. This avoids conflicts with methods of the inner
|
||||
/// type `T`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T: ?Sized> {
|
||||
ptr: Shared<RcBox<T>>,
|
||||
|
|
@ -229,12 +294,15 @@ impl<T> Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Unwraps the contained value if the `Rc<T>` has exactly one strong reference.
|
||||
/// Returns the contained value, if the `Rc` has exactly one strong reference.
|
||||
///
|
||||
/// Otherwise, an `Err` is returned with the same `Rc<T>`.
|
||||
/// Otherwise, an [`Err`][result] is returned with the same `Rc` that was
|
||||
/// passed in.
|
||||
///
|
||||
/// This will succeed even if there are outstanding weak references.
|
||||
///
|
||||
/// [result]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -245,7 +313,7 @@ impl<T> Rc<T> {
|
|||
///
|
||||
/// let x = Rc::new(4);
|
||||
/// let _y = x.clone();
|
||||
/// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
|
||||
/// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rc_unique", since = "1.4.0")]
|
||||
|
|
@ -268,7 +336,11 @@ impl<T> Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if `Rc::try_unwrap` would return `Ok`.
|
||||
/// Checks whether [`Rc::try_unwrap`][try_unwrap] would return
|
||||
/// [`Ok`][result].
|
||||
///
|
||||
/// [try_unwrap]: struct.Rc.html#method.try_unwrap
|
||||
/// [result]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -284,7 +356,7 @@ impl<T> Rc<T> {
|
|||
/// let x = Rc::new(4);
|
||||
/// let _y = x.clone();
|
||||
/// assert!(!Rc::would_unwrap(&x));
|
||||
/// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
|
||||
/// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4);
|
||||
/// ```
|
||||
#[unstable(feature = "rc_would_unwrap",
|
||||
reason = "just added for niche usecase",
|
||||
|
|
@ -294,8 +366,35 @@ impl<T> Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Rc<str> {
|
||||
/// Constructs a new `Rc<str>` from a string slice.
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "rustc_private",
|
||||
reason = "for internal use in rustc",
|
||||
issue = "0")]
|
||||
pub fn __from_str(value: &str) -> Rc<str> {
|
||||
unsafe {
|
||||
// Allocate enough space for `RcBox<str>`.
|
||||
let aligned_len = 2 + (value.len() + size_of::<usize>() - 1) / size_of::<usize>();
|
||||
let vec = RawVec::<usize>::with_capacity(aligned_len);
|
||||
let ptr = vec.ptr();
|
||||
forget(vec);
|
||||
// Initialize fields of `RcBox<str>`.
|
||||
*ptr.offset(0) = 1; // strong: Cell::new(1)
|
||||
*ptr.offset(1) = 1; // weak: Cell::new(1)
|
||||
ptr::copy_nonoverlapping(value.as_ptr(), ptr.offset(2) as *mut u8, value.len());
|
||||
// Combine the allocation address and the string length into a fat pointer to `RcBox`.
|
||||
let rcbox_ptr: *mut RcBox<str> = mem::transmute([ptr as usize, value.len()]);
|
||||
assert!(aligned_len * size_of::<usize>() == size_of_val(&*rcbox_ptr));
|
||||
Rc { ptr: Shared::new(rcbox_ptr) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Creates a new `Weak<T>` reference from this value.
|
||||
/// Creates a new [`Weak`][weak] pointer to this value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -312,7 +411,22 @@ impl<T: ?Sized> Rc<T> {
|
|||
Weak { ptr: this.ptr }
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
/// Gets the number of [`Weak`][weak] pointers to this value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(rc_counts)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// let _weak_five = Rc::downgrade(&five);
|
||||
///
|
||||
/// assert_eq!(1, Rc::weak_count(&five));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "rc_counts", reason = "not clearly useful",
|
||||
issue = "28356")]
|
||||
|
|
@ -320,7 +434,20 @@ impl<T: ?Sized> Rc<T> {
|
|||
this.weak() - 1
|
||||
}
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
/// Gets the number of strong (`Rc`) pointers to this value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(rc_counts)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// let _also_five = five.clone();
|
||||
///
|
||||
/// assert_eq!(2, Rc::strong_count(&five));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "rc_counts", reason = "not clearly useful",
|
||||
issue = "28356")]
|
||||
|
|
@ -328,8 +455,10 @@ impl<T: ?Sized> Rc<T> {
|
|||
this.strong()
|
||||
}
|
||||
|
||||
/// Returns true if there are no other `Rc` or `Weak<T>` values that share
|
||||
/// the same inner value.
|
||||
/// Returns true if there are no other `Rc` or [`Weak`][weak] pointers to
|
||||
/// this inner value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -349,10 +478,19 @@ impl<T: ?Sized> Rc<T> {
|
|||
Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the contained value if the `Rc<T>` has
|
||||
/// one strong reference and no weak references.
|
||||
/// Returns a mutable reference to the inner value, if there are
|
||||
/// no other `Rc` or [`Weak`][weak] pointers to the same value.
|
||||
///
|
||||
/// Returns `None` if the `Rc<T>` is not unique.
|
||||
/// Returns [`None`][option] otherwise, because it is not safe to
|
||||
/// mutate a shared value.
|
||||
///
|
||||
/// See also [`make_mut`][make_mut], which will [`clone`][clone]
|
||||
/// the inner value when it's shared.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
/// [make_mut]: struct.Rc.html#method.make_mut
|
||||
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -381,8 +519,8 @@ impl<T: ?Sized> Rc<T> {
|
|||
#[unstable(feature = "ptr_eq",
|
||||
reason = "newly added",
|
||||
issue = "36497")]
|
||||
/// Return whether two `Rc` references point to the same value
|
||||
/// (not just values that compare equal).
|
||||
/// Returns true if the two `Rc`s point to the same value (not
|
||||
/// just values that compare as equal).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -406,11 +544,17 @@ impl<T: ?Sized> Rc<T> {
|
|||
}
|
||||
|
||||
impl<T: Clone> Rc<T> {
|
||||
/// Make a mutable reference into the given `Rc<T>` by cloning the inner
|
||||
/// data if the `Rc<T>` doesn't have one strong reference and no weak
|
||||
/// references.
|
||||
/// Makes a mutable reference into the given `Rc`.
|
||||
///
|
||||
/// This is also referred to as a copy-on-write.
|
||||
/// If there are other `Rc` or [`Weak`][weak] pointers to the same value,
|
||||
/// then `make_mut` will invoke [`clone`][clone] on the inner value to
|
||||
/// ensure unique ownership. This is also referred to as clone-on-write.
|
||||
///
|
||||
/// See also [`get_mut`][get_mut], which will fail rather than cloning.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
|
||||
/// [get_mut]: struct.Rc.html#method.get_mut
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -419,16 +563,15 @@ impl<T: Clone> Rc<T> {
|
|||
///
|
||||
/// let mut data = Rc::new(5);
|
||||
///
|
||||
/// *Rc::make_mut(&mut data) += 1; // Won't clone anything
|
||||
/// let mut other_data = data.clone(); // Won't clone inner data
|
||||
/// *Rc::make_mut(&mut data) += 1; // Clones inner data
|
||||
/// *Rc::make_mut(&mut data) += 1; // Won't clone anything
|
||||
/// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything
|
||||
/// *Rc::make_mut(&mut data) += 1; // Won't clone anything
|
||||
/// let mut other_data = data.clone(); // Won't clone inner data
|
||||
/// *Rc::make_mut(&mut data) += 1; // Clones inner data
|
||||
/// *Rc::make_mut(&mut data) += 1; // Won't clone anything
|
||||
/// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything
|
||||
///
|
||||
/// // Note: data and other_data now point to different numbers
|
||||
/// // Now `data` and `other_data` point to different values.
|
||||
/// assert_eq!(*data, 8);
|
||||
/// assert_eq!(*other_data, 12);
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rc_unique", since = "1.4.0")]
|
||||
|
|
@ -470,30 +613,32 @@ impl<T: ?Sized> Deref for Rc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Rc<T> {
|
||||
/// Drops the `Rc<T>`.
|
||||
/// Drops the `Rc`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
/// count becomes zero and the only other references are `Weak<T>` ones,
|
||||
/// `drop`s the inner value.
|
||||
/// count reaches zero then the only other references (if any) are
|
||||
/// [`Weak`][weak], so we `drop` the inner value.
|
||||
///
|
||||
/// [weak]: struct.Weak.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// struct Foo;
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(five); // explicit drop
|
||||
/// impl Drop for Foo {
|
||||
/// fn drop(&mut self) {
|
||||
/// println!("dropped!");
|
||||
/// }
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// // stuff
|
||||
/// let foo = Rc::new(Foo);
|
||||
/// let foo2 = foo.clone();
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// drop(foo); // Doesn't print anything
|
||||
/// drop(foo2); // Prints "dropped!"
|
||||
/// ```
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
fn drop(&mut self) {
|
||||
|
|
@ -519,10 +664,10 @@ impl<T: ?Sized> Drop for Rc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for Rc<T> {
|
||||
/// Makes a clone of the `Rc<T>`.
|
||||
/// Makes a clone of the `Rc` pointer.
|
||||
///
|
||||
/// When you clone an `Rc<T>`, it will create another pointer to the data and
|
||||
/// increase the strong reference counter.
|
||||
/// This creates another pointer to the same inner value, increasing the
|
||||
/// strong reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -550,6 +695,7 @@ impl<T: Default> Default for Rc<T> {
|
|||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let x: Rc<i32> = Default::default();
|
||||
/// assert_eq!(*x, 0);
|
||||
/// ```
|
||||
#[inline]
|
||||
fn default() -> Rc<T> {
|
||||
|
|
@ -559,9 +705,9 @@ impl<T: Default> Default for Rc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
|
||||
/// Equality for two `Rc<T>`s.
|
||||
/// Equality for two `Rc`s.
|
||||
///
|
||||
/// Two `Rc<T>`s are equal if their inner value are equal.
|
||||
/// Two `Rc`s are equal if their inner values are equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -570,16 +716,16 @@ impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
|
|||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five == Rc::new(5);
|
||||
/// assert!(five == Rc::new(5));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Rc<T>) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
|
||||
/// Inequality for two `Rc<T>`s.
|
||||
/// Inequality for two `Rc`s.
|
||||
///
|
||||
/// Two `Rc<T>`s are unequal if their inner value are unequal.
|
||||
/// Two `Rc`s are unequal if their inner values are unequal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -588,7 +734,7 @@ impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
|
|||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five != Rc::new(5);
|
||||
/// assert!(five != Rc::new(6));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Rc<T>) -> bool {
|
||||
|
|
@ -601,7 +747,7 @@ impl<T: ?Sized + Eq> Eq for Rc<T> {}
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
||||
/// Partial comparison for two `Rc<T>`s.
|
||||
/// Partial comparison for two `Rc`s.
|
||||
///
|
||||
/// The two are compared by calling `partial_cmp()` on their inner values.
|
||||
///
|
||||
|
|
@ -609,17 +755,18 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five.partial_cmp(&Rc::new(5));
|
||||
/// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Rc::new(6)));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
|
||||
(**self).partial_cmp(&**other)
|
||||
}
|
||||
|
||||
/// Less-than comparison for two `Rc<T>`s.
|
||||
/// Less-than comparison for two `Rc`s.
|
||||
///
|
||||
/// The two are compared by calling `<` on their inner values.
|
||||
///
|
||||
|
|
@ -630,14 +777,14 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
|||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five < Rc::new(5);
|
||||
/// assert!(five < Rc::new(6));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &Rc<T>) -> bool {
|
||||
**self < **other
|
||||
}
|
||||
|
||||
/// 'Less-than or equal to' comparison for two `Rc<T>`s.
|
||||
/// 'Less than or equal to' comparison for two `Rc`s.
|
||||
///
|
||||
/// The two are compared by calling `<=` on their inner values.
|
||||
///
|
||||
|
|
@ -648,14 +795,14 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
|||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five <= Rc::new(5);
|
||||
/// assert!(five <= Rc::new(5));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &Rc<T>) -> bool {
|
||||
**self <= **other
|
||||
}
|
||||
|
||||
/// Greater-than comparison for two `Rc<T>`s.
|
||||
/// Greater-than comparison for two `Rc`s.
|
||||
///
|
||||
/// The two are compared by calling `>` on their inner values.
|
||||
///
|
||||
|
|
@ -666,14 +813,14 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
|||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five > Rc::new(5);
|
||||
/// assert!(five > Rc::new(4));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &Rc<T>) -> bool {
|
||||
**self > **other
|
||||
}
|
||||
|
||||
/// 'Greater-than or equal to' comparison for two `Rc<T>`s.
|
||||
/// 'Greater than or equal to' comparison for two `Rc`s.
|
||||
///
|
||||
/// The two are compared by calling `>=` on their inner values.
|
||||
///
|
||||
|
|
@ -684,7 +831,7 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
|||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five >= Rc::new(5);
|
||||
/// assert!(five >= Rc::new(5));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &Rc<T>) -> bool {
|
||||
|
|
@ -694,7 +841,7 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Ord> Ord for Rc<T> {
|
||||
/// Comparison for two `Rc<T>`s.
|
||||
/// Comparison for two `Rc`s.
|
||||
///
|
||||
/// The two are compared by calling `cmp()` on their inner values.
|
||||
///
|
||||
|
|
@ -702,10 +849,11 @@ impl<T: ?Sized + Ord> Ord for Rc<T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five.partial_cmp(&Rc::new(5));
|
||||
/// assert_eq!(Ordering::Less, five.cmp(&Rc::new(6)));
|
||||
/// ```
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Rc<T>) -> Ordering {
|
||||
|
|
@ -748,13 +896,18 @@ impl<T> From<T> for Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A weak version of `Rc<T>`.
|
||||
/// A weak version of [`Rc`][rc].
|
||||
///
|
||||
/// Weak references do not count when determining if the inner value should be
|
||||
/// dropped.
|
||||
/// `Weak` pointers do not count towards determining if the inner value
|
||||
/// should be dropped.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
/// The typical way to obtain a `Weak` pointer is to call
|
||||
/// [`Rc::downgrade`][downgrade].
|
||||
///
|
||||
/// See the [module-level documentation](./index.html) for more details.
|
||||
///
|
||||
/// [rc]: struct.Rc.html
|
||||
/// [downgrade]: struct.Rc.html#method.downgrade
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
ptr: Shared<RcBox<T>>,
|
||||
|
|
@ -769,10 +922,14 @@ impl<T: ?Sized> !marker::Sync for Weak<T> {}
|
|||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
|
||||
|
||||
impl<T> Weak<T> {
|
||||
/// Constructs a new `Weak<T>` without an accompanying instance of T.
|
||||
/// Constructs a new `Weak<T>`, without an accompanying instance of `T`.
|
||||
///
|
||||
/// This allocates memory for T, but does not initialize it. Calling
|
||||
/// Weak<T>::upgrade() on the return value always gives None.
|
||||
/// This allocates memory for `T`, but does not initialize it. Calling
|
||||
/// [`upgrade`][upgrade] on the return value always gives
|
||||
/// [`None`][option].
|
||||
///
|
||||
/// [upgrade]: struct.Weak.html#method.upgrade
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -780,6 +937,7 @@ impl<T> Weak<T> {
|
|||
/// use std::rc::Weak;
|
||||
///
|
||||
/// let empty: Weak<i64> = Weak::new();
|
||||
/// assert!(empty.upgrade().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
pub fn new() -> Weak<T> {
|
||||
|
|
@ -796,12 +954,13 @@ impl<T> Weak<T> {
|
|||
}
|
||||
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
/// Upgrades the `Weak` pointer to an [`Rc`][rc], if possible.
|
||||
///
|
||||
/// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
|
||||
/// Returns [`None`][option] if the strong count has reached zero and the
|
||||
/// inner value was destroyed.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was
|
||||
/// destroyed.
|
||||
/// [rc]: struct.Rc.html
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -813,6 +972,13 @@ impl<T: ?Sized> Weak<T> {
|
|||
/// let weak_five = Rc::downgrade(&five);
|
||||
///
|
||||
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
|
||||
/// assert!(strong_five.is_some());
|
||||
///
|
||||
/// // Destroy all strong pointers.
|
||||
/// drop(strong_five);
|
||||
/// drop(five);
|
||||
///
|
||||
/// assert!(weak_five.upgrade().is_none());
|
||||
/// ```
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||
|
|
@ -827,7 +993,7 @@ impl<T: ?Sized> Weak<T> {
|
|||
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
impl<T: ?Sized> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
/// Drops the `Weak` pointer.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
///
|
||||
|
|
@ -836,21 +1002,22 @@ impl<T: ?Sized> Drop for Weak<T> {
|
|||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// let weak_five = Rc::downgrade(&five);
|
||||
/// struct Foo;
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(weak_five); // explicit drop
|
||||
/// impl Drop for Foo {
|
||||
/// fn drop(&mut self) {
|
||||
/// println!("dropped!");
|
||||
/// }
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// let weak_five = Rc::downgrade(&five);
|
||||
///
|
||||
/// // stuff
|
||||
/// let foo = Rc::new(Foo);
|
||||
/// let weak_foo = Rc::downgrade(&foo);
|
||||
/// let other_weak_foo = weak_foo.clone();
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// drop(weak_foo); // Doesn't print anything
|
||||
/// drop(foo); // Prints "dropped!"
|
||||
///
|
||||
/// assert!(other_weak_foo.upgrade().is_none());
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
|
@ -868,9 +1035,10 @@ impl<T: ?Sized> Drop for Weak<T> {
|
|||
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
impl<T: ?Sized> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
/// Makes a clone of the `Weak` pointer.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
/// This creates another pointer to the same inner value, increasing the
|
||||
/// weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -897,7 +1065,23 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
|
|||
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
impl<T> Default for Weak<T> {
|
||||
/// Creates a new `Weak<T>`.
|
||||
/// Constructs a new `Weak<T>`, without an accompanying instance of `T`.
|
||||
///
|
||||
/// This allocates memory for `T`, but does not initialize it. Calling
|
||||
/// [`upgrade`][upgrade] on the return value always gives
|
||||
/// [`None`][option].
|
||||
///
|
||||
/// [upgrade]: struct.Weak.html#method.upgrade
|
||||
/// [option]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Weak;
|
||||
///
|
||||
/// let empty: Weak<i64> = Default::default();
|
||||
/// assert!(empty.upgrade().is_none());
|
||||
/// ```
|
||||
fn default() -> Weak<T> {
|
||||
Weak::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,25 @@ fn main() {
|
|||
println!("cargo:rustc-cfg=cargobuild");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let host = env::var("HOST").unwrap();
|
||||
let target = env::var("TARGET").expect("TARGET was not set");
|
||||
let host = env::var("HOST").expect("HOST was not set");
|
||||
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let src_dir = env::current_dir().unwrap();
|
||||
|
||||
// FIXME: This is a hack to support building targets that don't
|
||||
// support jemalloc alongside hosts that do. The jemalloc build is
|
||||
// controlled by a feature of the std crate, and if that feature
|
||||
// changes between targets, it invalidates the fingerprint of
|
||||
// std's build script (this is a cargo bug); so we must ensure
|
||||
// that the feature set used by std is the same across all
|
||||
// targets, which means we have to build the alloc_jemalloc crate
|
||||
// for targets like emscripten, even if we don't use it.
|
||||
if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
|
||||
target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") {
|
||||
println!("cargo:rustc-cfg=dummy_jemalloc");
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
|
||||
let jemalloc = PathBuf::from(jemalloc);
|
||||
println!("cargo:rustc-link-search=native={}",
|
||||
|
|
@ -46,16 +60,16 @@ fn main() {
|
|||
// only msvc returns None for ar so unwrap is okay
|
||||
let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
|
||||
let cflags = compiler.args()
|
||||
.iter()
|
||||
.map(|s| s.to_str().unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
.iter()
|
||||
.map(|s| s.to_str().unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
let mut stack = src_dir.join("../jemalloc")
|
||||
.read_dir()
|
||||
.unwrap()
|
||||
.map(|e| e.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
.read_dir()
|
||||
.unwrap()
|
||||
.map(|e| e.unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
while let Some(entry) = stack.pop() {
|
||||
let path = entry.path();
|
||||
if entry.file_type().unwrap().is_dir() {
|
||||
|
|
@ -137,10 +151,10 @@ fn main() {
|
|||
|
||||
run(&mut cmd);
|
||||
run(Command::new("make")
|
||||
.current_dir(&build_dir)
|
||||
.arg("build_lib_static")
|
||||
.arg("-j")
|
||||
.arg(env::var("NUM_JOBS").unwrap()));
|
||||
.current_dir(&build_dir)
|
||||
.arg("build_lib_static")
|
||||
.arg("-j")
|
||||
.arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
|
||||
|
||||
if target.contains("windows") {
|
||||
println!("cargo:rustc-link-lib=static=jemalloc");
|
||||
|
|
|
|||
|
|
@ -23,124 +23,170 @@
|
|||
|
||||
extern crate libc;
|
||||
|
||||
use libc::{c_int, c_void, size_t};
|
||||
pub use imp::*;
|
||||
|
||||
// Linkage directives to pull in jemalloc and its dependencies.
|
||||
//
|
||||
// On some platforms we need to be sure to link in `pthread` which jemalloc
|
||||
// depends on, and specifically on android we need to also link to libgcc.
|
||||
// Currently jemalloc is compiled with gcc which will generate calls to
|
||||
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
|
||||
// libcompiler-rt), so link that in to get that support.
|
||||
#[link(name = "jemalloc", kind = "static")]
|
||||
#[cfg_attr(target_os = "android", link(name = "gcc"))]
|
||||
#[cfg_attr(all(not(windows),
|
||||
not(target_os = "android"),
|
||||
not(target_env = "musl")),
|
||||
link(name = "pthread"))]
|
||||
#[cfg(not(cargobuild))]
|
||||
extern "C" {}
|
||||
// See comments in build.rs for why we sometimes build a crate that does nothing
|
||||
#[cfg(not(dummy_jemalloc))]
|
||||
mod imp {
|
||||
use libc::{c_int, c_void, size_t};
|
||||
|
||||
// Note that the symbols here are prefixed by default on OSX and Windows (we
|
||||
// don't explicitly request it), and on Android and DragonFly we explicitly
|
||||
// request it as unprefixing cause segfaults (mismatches in allocators).
|
||||
extern "C" {
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_mallocx")]
|
||||
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_rallocx")]
|
||||
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_xallocx")]
|
||||
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_sdallocx")]
|
||||
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_nallocx")]
|
||||
fn nallocx(size: size_t, flags: c_int) -> size_t;
|
||||
}
|
||||
// Linkage directives to pull in jemalloc and its dependencies.
|
||||
//
|
||||
// On some platforms we need to be sure to link in `pthread` which jemalloc
|
||||
// depends on, and specifically on android we need to also link to libgcc.
|
||||
// Currently jemalloc is compiled with gcc which will generate calls to
|
||||
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
|
||||
// libcompiler-rt), so link that in to get that support.
|
||||
#[link(name = "jemalloc", kind = "static")]
|
||||
#[cfg_attr(target_os = "android", link(name = "gcc"))]
|
||||
#[cfg_attr(all(not(windows),
|
||||
not(target_os = "android"),
|
||||
not(target_env = "musl")),
|
||||
link(name = "pthread"))]
|
||||
#[cfg(not(cargobuild))]
|
||||
extern "C" {}
|
||||
|
||||
// The minimum alignment guaranteed by the architecture. This value is used to
|
||||
// add fast paths for low alignment values. In practice, the alignment is a
|
||||
// constant at the call site and the branch will be optimized out.
|
||||
#[cfg(all(any(target_arch = "arm",
|
||||
target_arch = "mips",
|
||||
target_arch = "powerpc")))]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
// Note that the symbols here are prefixed by default on OSX and Windows (we
|
||||
// don't explicitly request it), and on Android and DragonFly we explicitly
|
||||
// request it as unprefixing cause segfaults (mismatches in allocators).
|
||||
extern "C" {
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_mallocx")]
|
||||
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_rallocx")]
|
||||
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_xallocx")]
|
||||
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_sdallocx")]
|
||||
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
|
||||
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
|
||||
target_os = "dragonfly", target_os = "windows"),
|
||||
link_name = "je_nallocx")]
|
||||
fn nallocx(size: size_t, flags: c_int) -> size_t;
|
||||
}
|
||||
|
||||
// MALLOCX_ALIGN(a) macro
|
||||
fn mallocx_align(a: usize) -> c_int {
|
||||
a.trailing_zeros() as c_int
|
||||
}
|
||||
// The minimum alignment guaranteed by the architecture. This value is used to
|
||||
// add fast paths for low alignment values. In practice, the alignment is a
|
||||
// constant at the call site and the branch will be optimized out.
|
||||
#[cfg(all(any(target_arch = "arm",
|
||||
target_arch = "mips",
|
||||
target_arch = "powerpc")))]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
fn align_to_flags(align: usize) -> c_int {
|
||||
if align <= MIN_ALIGN {
|
||||
// MALLOCX_ALIGN(a) macro
|
||||
fn mallocx_align(a: usize) -> c_int {
|
||||
a.trailing_zeros() as c_int
|
||||
}
|
||||
|
||||
fn align_to_flags(align: usize) -> c_int {
|
||||
if align <= MIN_ALIGN {
|
||||
0
|
||||
} else {
|
||||
mallocx_align(align)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { mallocx(size as size_t, flags) as *mut u8 }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
|
||||
_old_size: usize,
|
||||
size: usize,
|
||||
align: usize)
|
||||
-> *mut u8 {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
|
||||
_old_size: usize,
|
||||
size: usize,
|
||||
align: usize)
|
||||
-> usize {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { nallocx(size as size_t, flags) as usize }
|
||||
}
|
||||
|
||||
// These symbols are used by jemalloc on android but the really old android
|
||||
// we're building on doesn't have them defined, so just make sure the symbols
|
||||
// are available.
|
||||
#[no_mangle]
|
||||
#[cfg(target_os = "android")]
|
||||
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
|
||||
_postfork_parent: *mut u8,
|
||||
_postfork_child: *mut u8)
|
||||
-> i32 {
|
||||
0
|
||||
} else {
|
||||
mallocx_align(align)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { mallocx(size as size_t, flags) as *mut u8 }
|
||||
}
|
||||
#[cfg(dummy_jemalloc)]
|
||||
mod imp {
|
||||
fn bogus() -> ! {
|
||||
panic!("jemalloc is not implemented for this platform");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
|
||||
_old_size: usize,
|
||||
size: usize,
|
||||
align: usize)
|
||||
-> *mut u8 {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
|
||||
bogus()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
|
||||
_old_size: usize,
|
||||
size: usize,
|
||||
align: usize)
|
||||
-> usize {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
|
||||
_old_size: usize,
|
||||
_size: usize,
|
||||
_align: usize)
|
||||
-> *mut u8 {
|
||||
bogus()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
|
||||
_old_size: usize,
|
||||
_size: usize,
|
||||
_align: usize)
|
||||
-> usize {
|
||||
bogus()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
|
||||
let flags = align_to_flags(align);
|
||||
unsafe { nallocx(size as size_t, flags) as usize }
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
|
||||
bogus()
|
||||
}
|
||||
|
||||
// These symbols are used by jemalloc on android but the really old android
|
||||
// we're building on doesn't have them defined, so just make sure the symbols
|
||||
// are available.
|
||||
#[no_mangle]
|
||||
#[cfg(target_os = "android")]
|
||||
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
|
||||
_postfork_parent: *mut u8,
|
||||
_postfork_child: *mut u8)
|
||||
-> i32 {
|
||||
0
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
|
||||
bogus()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@
|
|||
target_arch = "mips",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "asmjs")))]
|
||||
target_arch = "asmjs",
|
||||
target_arch = "wasm32")))]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
|
|
@ -165,6 +166,7 @@ mod imp {
|
|||
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
|
||||
fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
|
||||
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
|
||||
fn GetLastError() -> DWORD;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
@ -220,11 +222,7 @@ mod imp {
|
|||
HEAP_REALLOC_IN_PLACE_ONLY,
|
||||
ptr as LPVOID,
|
||||
size as SIZE_T) as *mut u8;
|
||||
if new.is_null() {
|
||||
old_size
|
||||
} else {
|
||||
size
|
||||
}
|
||||
if new.is_null() { old_size } else { size }
|
||||
} else {
|
||||
old_size
|
||||
}
|
||||
|
|
@ -233,11 +231,11 @@ mod imp {
|
|||
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
|
||||
if align <= MIN_ALIGN {
|
||||
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
|
||||
debug_assert!(err != 0);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
|
||||
} else {
|
||||
let header = get_header(ptr);
|
||||
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
|
||||
debug_assert!(err != 0);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@
|
|||
//! of individual objects while the arena itself is still alive. The benefit
|
||||
//! of an arena is very fast allocation; just a pointer bump.
|
||||
//!
|
||||
//! This crate has two arenas implemented: `TypedArena`, which is a simpler
|
||||
//! arena but can only hold objects of a single type, and `Arena`, which is a
|
||||
//! more complex, slower arena which can hold objects of any type.
|
||||
//! This crate implements `TypedArena`, a simple arena that can only hold
|
||||
//! objects of a single type.
|
||||
|
||||
#![crate_name = "arena"]
|
||||
#![unstable(feature = "rustc_private", issue = "27812")]
|
||||
|
|
@ -47,11 +46,12 @@ use std::intrinsics;
|
|||
use std::marker::{PhantomData, Send};
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
use alloc::heap;
|
||||
use alloc::raw_vec::RawVec;
|
||||
|
||||
/// A faster arena that can hold objects of only one type.
|
||||
/// An arena that can hold objects of only one type.
|
||||
pub struct TypedArena<T> {
|
||||
/// A pointer to the next object to be allocated.
|
||||
ptr: Cell<*mut T>,
|
||||
|
|
@ -60,7 +60,7 @@ pub struct TypedArena<T> {
|
|||
/// reached, a new chunk is allocated.
|
||||
end: Cell<*mut T>,
|
||||
|
||||
/// A vector arena segments.
|
||||
/// A vector of arena chunks.
|
||||
chunks: RefCell<Vec<TypedArenaChunk<T>>>,
|
||||
|
||||
/// Marker indicating that dropping the arena causes its owned
|
||||
|
|
@ -69,7 +69,7 @@ pub struct TypedArena<T> {
|
|||
}
|
||||
|
||||
struct TypedArenaChunk<T> {
|
||||
/// Pointer to the next arena segment.
|
||||
/// The raw storage for the arena chunk.
|
||||
storage: RawVec<T>,
|
||||
}
|
||||
|
||||
|
|
@ -117,26 +117,16 @@ impl<T> TypedArenaChunk<T> {
|
|||
const PAGE: usize = 4096;
|
||||
|
||||
impl<T> TypedArena<T> {
|
||||
/// Creates a new `TypedArena` with preallocated space for many objects.
|
||||
/// Creates a new `TypedArena`.
|
||||
#[inline]
|
||||
pub fn new() -> TypedArena<T> {
|
||||
// Reserve at least one page.
|
||||
let elem_size = cmp::max(1, mem::size_of::<T>());
|
||||
TypedArena::with_capacity(PAGE / elem_size)
|
||||
}
|
||||
|
||||
/// Creates a new `TypedArena` with preallocated space for the given number of
|
||||
/// objects.
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> TypedArena<T> {
|
||||
unsafe {
|
||||
let chunk = TypedArenaChunk::<T>::new(cmp::max(1, capacity));
|
||||
TypedArena {
|
||||
ptr: Cell::new(chunk.start()),
|
||||
end: Cell::new(chunk.end()),
|
||||
chunks: RefCell::new(vec![chunk]),
|
||||
_own: PhantomData,
|
||||
}
|
||||
TypedArena {
|
||||
// We set both `ptr` and `end` to 0 so that the first call to
|
||||
// alloc() will trigger a grow().
|
||||
ptr: Cell::new(0 as *mut T),
|
||||
end: Cell::new(0 as *mut T),
|
||||
chunks: RefCell::new(vec![]),
|
||||
_own: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +134,7 @@ impl<T> TypedArena<T> {
|
|||
#[inline]
|
||||
pub fn alloc(&self, object: T) -> &mut T {
|
||||
if self.ptr == self.end {
|
||||
self.grow()
|
||||
self.grow(1)
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
|
@ -165,35 +155,79 @@ impl<T> TypedArena<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Allocates a slice of objects that are copy into the `TypedArena`, returning a mutable
|
||||
/// reference to it. Will panic if passed a zero-sized types.
|
||||
///
|
||||
/// Panics:
|
||||
/// - Zero-sized types
|
||||
/// - Zero-length slices
|
||||
#[inline]
|
||||
pub fn alloc_slice(&self, slice: &[T]) -> &mut [T]
|
||||
where T: Copy {
|
||||
assert!(mem::size_of::<T>() != 0);
|
||||
assert!(slice.len() != 0);
|
||||
|
||||
let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
|
||||
let at_least_bytes = slice.len() * mem::size_of::<T>();
|
||||
if available_capacity_bytes < at_least_bytes {
|
||||
self.grow(slice.len());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let start_ptr = self.ptr.get();
|
||||
let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len());
|
||||
self.ptr.set(start_ptr.offset(arena_slice.len() as isize));
|
||||
arena_slice.copy_from_slice(slice);
|
||||
arena_slice
|
||||
}
|
||||
}
|
||||
|
||||
/// Grows the arena.
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn grow(&self) {
|
||||
fn grow(&self, n: usize) {
|
||||
unsafe {
|
||||
let mut chunks = self.chunks.borrow_mut();
|
||||
let prev_capacity = chunks.last().unwrap().storage.cap();
|
||||
let new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
if chunks.last_mut().unwrap().storage.double_in_place() {
|
||||
self.end.set(chunks.last().unwrap().end());
|
||||
let (chunk, mut new_capacity);
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
|
||||
let currently_used_cap = used_bytes / mem::size_of::<T>();
|
||||
if last_chunk.storage.reserve_in_place(currently_used_cap, n) {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
let prev_capacity = last_chunk.storage.cap();
|
||||
loop {
|
||||
new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
if new_capacity >= currently_used_cap + n {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
let elem_size = cmp::max(1, mem::size_of::<T>());
|
||||
new_capacity = cmp::max(n, PAGE / elem_size);
|
||||
}
|
||||
chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the arena. Deallocates all but the longest chunk which may be reused.
|
||||
pub fn clear(&mut self) {
|
||||
unsafe {
|
||||
// Clear the last chunk, which is partially filled.
|
||||
let mut chunks_borrow = self.chunks.borrow_mut();
|
||||
let last_idx = chunks_borrow.len() - 1;
|
||||
self.clear_last_chunk(&mut chunks_borrow[last_idx]);
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..last_idx) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
if let Some(mut last_chunk) = chunks_borrow.pop() {
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
}
|
||||
chunks_borrow.push(last_chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -230,13 +264,14 @@ impl<T> Drop for TypedArena<T> {
|
|||
unsafe {
|
||||
// Determine how much was filled.
|
||||
let mut chunks_borrow = self.chunks.borrow_mut();
|
||||
let mut last_chunk = chunks_borrow.pop().unwrap();
|
||||
// Drop the contents of the last chunk.
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
if let Some(mut last_chunk) = chunks_borrow.pop() {
|
||||
// Drop the contents of the last chunk.
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
}
|
||||
}
|
||||
// RawVec handles deallocation of `last_chunk` and `self.chunks`.
|
||||
}
|
||||
|
|
@ -260,6 +295,12 @@ mod tests {
|
|||
z: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_unused() {
|
||||
let arena: TypedArena<Point> = TypedArena::new();
|
||||
assert!(arena.chunks.borrow().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arena_alloc_nested() {
|
||||
struct Inner {
|
||||
|
|
@ -296,9 +337,8 @@ mod tests {
|
|||
|
||||
let arena = Wrap(TypedArena::new());
|
||||
|
||||
let result = arena.alloc_outer(|| {
|
||||
Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }
|
||||
});
|
||||
let result =
|
||||
arena.alloc_outer(|| Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) });
|
||||
|
||||
assert_eq!(result.inner.value, 10);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -535,6 +535,7 @@ impl<T: Ord> BinaryHeap<T> {
|
|||
///
|
||||
/// ```
|
||||
/// #![feature(binary_heap_extras)]
|
||||
/// #![allow(deprecated)]
|
||||
///
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
|
|
@ -549,6 +550,7 @@ impl<T: Ord> BinaryHeap<T> {
|
|||
#[unstable(feature = "binary_heap_extras",
|
||||
reason = "needs to be audited",
|
||||
issue = "28147")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")]
|
||||
pub fn push_pop(&mut self, mut item: T) -> T {
|
||||
match self.data.get_mut(0) {
|
||||
None => return item,
|
||||
|
|
@ -575,6 +577,7 @@ impl<T: Ord> BinaryHeap<T> {
|
|||
///
|
||||
/// ```
|
||||
/// #![feature(binary_heap_extras)]
|
||||
/// #![allow(deprecated)]
|
||||
///
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
|
|
@ -587,6 +590,7 @@ impl<T: Ord> BinaryHeap<T> {
|
|||
#[unstable(feature = "binary_heap_extras",
|
||||
reason = "needs to be audited",
|
||||
issue = "28147")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")]
|
||||
pub fn replace(&mut self, mut item: T) -> Option<T> {
|
||||
if !self.is_empty() {
|
||||
swap(&mut item, &mut self.data[0]);
|
||||
|
|
@ -1029,7 +1033,7 @@ pub struct Drain<'a, T: 'a> {
|
|||
iter: vec::Drain<'a, T>,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> Iterator for Drain<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
|
|
@ -1044,7 +1048,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
|
|
@ -1052,7 +1056,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
use core::cmp::Ordering;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::Deref;
|
||||
use core::ops::{Add, AddAssign, Deref};
|
||||
|
||||
use fmt;
|
||||
|
||||
|
|
@ -86,16 +86,29 @@ impl<T> ToOwned for T where T: Clone {
|
|||
/// ```
|
||||
/// use std::borrow::Cow;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// fn abs_all(input: &mut Cow<[i32]>) {
|
||||
/// for i in 0..input.len() {
|
||||
/// let v = input[i];
|
||||
/// if v < 0 {
|
||||
/// // clones into a vector the first time (if not already owned)
|
||||
/// // Clones into a vector if not already owned.
|
||||
/// input.to_mut()[i] = -v;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // No clone occurs because `input` doesn't need to be mutated.
|
||||
/// let slice = [0, 1, 2];
|
||||
/// let mut input = Cow::from(&slice[..]);
|
||||
/// abs_all(&mut input);
|
||||
///
|
||||
/// // Clone occurs because `input` needs to be mutated.
|
||||
/// let slice = [-1, 0, 1];
|
||||
/// let mut input = Cow::from(&slice[..]);
|
||||
/// abs_all(&mut input);
|
||||
///
|
||||
/// // No clone occurs because `input` is already owned.
|
||||
/// let mut input = Cow::from(vec![-1, 0, 1]);
|
||||
/// abs_all(&mut input);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub enum Cow<'a, B: ?Sized + 'a>
|
||||
|
|
@ -270,3 +283,49 @@ impl<'a, T: ?Sized + ToOwned> AsRef<T> for Cow<'a, T> {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.13.0")]
|
||||
impl<'a> Add<&'a str> for Cow<'a, str> {
|
||||
type Output = Cow<'a, str>;
|
||||
|
||||
fn add(self, rhs: &'a str) -> Self {
|
||||
if self == "" {
|
||||
Cow::Borrowed(rhs)
|
||||
} else if rhs == "" {
|
||||
self
|
||||
} else {
|
||||
Cow::Owned(self.into_owned() + rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.13.0")]
|
||||
impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
|
||||
type Output = Cow<'a, str>;
|
||||
|
||||
fn add(self, rhs: Cow<'a, str>) -> Self {
|
||||
if self == "" {
|
||||
rhs
|
||||
} else if rhs == "" {
|
||||
self
|
||||
} else {
|
||||
Cow::Owned(self.into_owned() + rhs.borrow())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.13.0")]
|
||||
impl<'a> AddAssign<&'a str> for Cow<'a, str> {
|
||||
fn add_assign(&mut self, rhs: &'a str) {
|
||||
if rhs == "" { return; }
|
||||
self.to_mut().push_str(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.13.0")]
|
||||
impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
|
||||
fn add_assign(&mut self, rhs: Cow<'a, str>) {
|
||||
if rhs == "" { return; }
|
||||
self.to_mut().push_str(rhs.borrow());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ pub struct BTreeMap<K, V> {
|
|||
length: usize,
|
||||
}
|
||||
|
||||
#[stable(feature = "btree_drop", since = "1.7.0")]
|
||||
impl<K, V> Drop for BTreeMap<K, V> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
fn drop(&mut self) {
|
||||
|
|
@ -146,6 +147,7 @@ impl<K, V> Drop for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
|
||||
fn clone(&self) -> BTreeMap<K, V> {
|
||||
fn clone_subtree<K: Clone, V: Clone>(node: node::NodeRef<marker::Immut,
|
||||
|
|
@ -1125,6 +1127,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
|
|
@ -1134,6 +1137,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
|
|
@ -1154,6 +1158,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
if self.length == 0 {
|
||||
|
|
@ -1165,12 +1170,14 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.length
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> Clone for Iter<'a, K, V> {
|
||||
fn clone(&self) -> Iter<'a, K, V> {
|
||||
Iter {
|
||||
|
|
@ -1180,6 +1187,7 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
type IntoIter = IterMut<'a, K, V>;
|
||||
|
|
@ -1189,6 +1197,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
|
|
@ -1206,6 +1215,7 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
if self.length == 0 {
|
||||
|
|
@ -1217,6 +1227,7 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.length
|
||||
|
|
@ -1226,6 +1237,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K, V> IntoIterator for BTreeMap<K, V> {
|
||||
type Item = (K, V);
|
||||
type IntoIter = IntoIter<K, V>;
|
||||
|
|
@ -1244,6 +1256,7 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "btree_drop", since = "1.7.0")]
|
||||
impl<K, V> Drop for IntoIter<K, V> {
|
||||
fn drop(&mut self) {
|
||||
for _ in &mut *self {
|
||||
|
|
@ -1260,6 +1273,7 @@ impl<K, V> Drop for IntoIter<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K, V> Iterator for IntoIter<K, V> {
|
||||
type Item = (K, V);
|
||||
|
||||
|
|
@ -1304,6 +1318,7 @@ impl<K, V> Iterator for IntoIter<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
|
||||
fn next_back(&mut self) -> Option<(K, V)> {
|
||||
if self.length == 0 {
|
||||
|
|
@ -1342,6 +1357,7 @@ impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K, V> ExactSizeIterator for IntoIter<K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.length
|
||||
|
|
@ -1351,6 +1367,7 @@ impl<K, V> ExactSizeIterator for IntoIter<K, V> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<K, V> FusedIterator for IntoIter<K, V> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> Iterator for Keys<'a, K, V> {
|
||||
type Item = &'a K;
|
||||
|
||||
|
|
@ -1363,12 +1380,14 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<&'a K> {
|
||||
self.inner.next_back().map(|(k, _)| k)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
|
|
@ -1378,12 +1397,14 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> Clone for Keys<'a, K, V> {
|
||||
fn clone(&self) -> Keys<'a, K, V> {
|
||||
Keys { inner: self.inner.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> Iterator for Values<'a, K, V> {
|
||||
type Item = &'a V;
|
||||
|
||||
|
|
@ -1396,12 +1417,14 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<&'a V> {
|
||||
self.inner.next_back().map(|(_, v)| v)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
|
||||
fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
|
|
@ -1411,6 +1434,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K, V> Clone for Values<'a, K, V> {
|
||||
fn clone(&self) -> Values<'a, K, V> {
|
||||
Values { inner: self.inner.clone() }
|
||||
|
|
@ -1635,6 +1659,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> BTreeMap<K, V> {
|
||||
let mut map = BTreeMap::new();
|
||||
|
|
@ -1643,6 +1668,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
|
||||
#[inline]
|
||||
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
||||
|
|
@ -1652,12 +1678,14 @@ impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap<K, V> {
|
||||
fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
for elt in self {
|
||||
|
|
@ -1666,6 +1694,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Ord, V> Default for BTreeMap<K, V> {
|
||||
/// Creates an empty `BTreeMap<K, V>`.
|
||||
fn default() -> BTreeMap<K, V> {
|
||||
|
|
@ -1673,14 +1702,17 @@ impl<K: Ord, V> Default for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: PartialEq, V: PartialEq> PartialEq for BTreeMap<K, V> {
|
||||
fn eq(&self, other: &BTreeMap<K, V>) -> bool {
|
||||
self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Eq, V: Eq> Eq for BTreeMap<K, V> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: PartialOrd, V: PartialOrd> PartialOrd for BTreeMap<K, V> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &BTreeMap<K, V>) -> Option<Ordering> {
|
||||
|
|
@ -1688,6 +1720,7 @@ impl<K: PartialOrd, V: PartialOrd> PartialOrd for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Ord, V: Ord> Ord for BTreeMap<K, V> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &BTreeMap<K, V>) -> Ordering {
|
||||
|
|
@ -1695,12 +1728,14 @@ impl<K: Ord, V: Ord> Ord for BTreeMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_map().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
|
||||
where K: Borrow<Q>,
|
||||
Q: Ord
|
||||
|
|
|
|||
|
|
@ -779,6 +779,7 @@ impl<T: Debug> Debug for BTreeSet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Clone for Iter<'a, T> {
|
||||
fn clone(&self) -> Iter<'a, T> {
|
||||
Iter { iter: self.iter.clone() }
|
||||
|
|
@ -864,6 +865,7 @@ fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Clone for Difference<'a, T> {
|
||||
fn clone(&self) -> Difference<'a, T> {
|
||||
Difference {
|
||||
|
|
@ -901,6 +903,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T: Ord> FusedIterator for Difference<'a, T> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Clone for SymmetricDifference<'a, T> {
|
||||
fn clone(&self) -> SymmetricDifference<'a, T> {
|
||||
SymmetricDifference {
|
||||
|
|
@ -934,6 +937,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Clone for Intersection<'a, T> {
|
||||
fn clone(&self) -> Intersection<'a, T> {
|
||||
Intersection {
|
||||
|
|
@ -977,6 +981,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Clone for Union<'a, T> {
|
||||
fn clone(&self) -> Union<'a, T> {
|
||||
Union {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ impl<E> Clone for EnumSet<E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<E: CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_set().entries(self).finish()
|
||||
|
|
@ -277,7 +276,6 @@ impl<E: CLike> FromIterator<E> for EnumSet<E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike
|
||||
{
|
||||
type Item = E;
|
||||
|
|
@ -296,7 +294,6 @@ impl<E: CLike> Extend<E> for EnumSet<E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet<E> {
|
||||
fn extend<I: IntoIterator<Item = &'a E>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
|
|
|
|||
|
|
@ -261,8 +261,8 @@
|
|||
//! This and `writeln` are two macros which are used to emit the format string
|
||||
//! to a specified stream. This is used to prevent intermediate allocations of
|
||||
//! format strings and instead directly write the output. Under the hood, this
|
||||
//! function is actually invoking the `write` function defined in this module.
|
||||
//! Example usage is:
|
||||
//! function is actually invoking the `write_fmt` function defined on the
|
||||
//! `std::io::Write` trait. Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_must_use)]
|
||||
|
|
@ -327,7 +327,7 @@
|
|||
//! format := '{' [ argument ] [ ':' format_spec ] '}'
|
||||
//! argument := integer | identifier
|
||||
//!
|
||||
//! format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type]
|
||||
//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
|
||||
//! fill := character
|
||||
//! align := '<' | '^' | '>'
|
||||
//! sign := '+' | '-'
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
#![feature(step_by)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
|
||||
#![cfg_attr(test, feature(rand, test))]
|
||||
|
||||
#![no_std]
|
||||
|
|
|
|||
|
|
@ -1294,6 +1294,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn test_send() {
|
||||
let n = list_from(&[1, 2, 3]);
|
||||
thread::spawn(move || {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ macro_rules! vec {
|
|||
}
|
||||
|
||||
/// Use the syntax described in `std::fmt` to create a value of type `String`.
|
||||
/// See `std::fmt` for more information.
|
||||
/// See [`std::fmt`][fmt] for more information.
|
||||
///
|
||||
/// [fmt]: ../std/fmt/index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
//!
|
||||
//! ## Structs
|
||||
//!
|
||||
//! There are several structs that are useful for slices, such as `Iter`, which
|
||||
//! There are several structs that are useful for slices, such as [`Iter`], which
|
||||
//! represents iteration over a slice.
|
||||
//!
|
||||
//! ## Trait Implementations
|
||||
|
|
@ -44,9 +44,9 @@
|
|||
//! There are several implementations of common traits for slices. Some examples
|
||||
//! include:
|
||||
//!
|
||||
//! * `Clone`
|
||||
//! * `Eq`, `Ord` - for slices whose element type are `Eq` or `Ord`.
|
||||
//! * `Hash` - for slices whose element type is `Hash`
|
||||
//! * [`Clone`]
|
||||
//! * [`Eq`], [`Ord`] - for slices whose element type are [`Eq`] or [`Ord`].
|
||||
//! * [`Hash`] - for slices whose element type is [`Hash`].
|
||||
//!
|
||||
//! ## Iteration
|
||||
//!
|
||||
|
|
@ -73,12 +73,24 @@
|
|||
//! the element type of the slice is `i32`, the element type of the iterator is
|
||||
//! `&mut i32`.
|
||||
//!
|
||||
//! * `.iter()` and `.iter_mut()` are the explicit methods to return the default
|
||||
//! * [`.iter()`] and [`.iter_mut()`] are the explicit methods to return the default
|
||||
//! iterators.
|
||||
//! * Further methods that return iterators are `.split()`, `.splitn()`,
|
||||
//! `.chunks()`, `.windows()` and more.
|
||||
//! * Further methods that return iterators are [`.split()`], [`.splitn()`],
|
||||
//! [`.chunks()`], [`.windows()`] and more.
|
||||
//!
|
||||
//! *[See also the slice primitive type](../../std/primitive.slice.html).*
|
||||
//!
|
||||
//! [`Clone`]: ../../std/clone/trait.Clone.html
|
||||
//! [`Eq`]: ../../std/cmp/trait.Eq.html
|
||||
//! [`Ord`]: ../../std/cmp/trait.Ord.html
|
||||
//! [`Iter`]: struct.Iter.html
|
||||
//! [`Hash`]: ../../std/hash/trait.Hash.html
|
||||
//! [`.iter()`]: ../../std/primitive.slice.html#method.iter
|
||||
//! [`.iter_mut()`]: ../../std/primitive.slice.html#method.iter_mut
|
||||
//! [`.split()`]: ../../std/primitive.slice.html#method.split
|
||||
//! [`.splitn()`]: ../../std/primitive.slice.html#method.splitn
|
||||
//! [`.chunks()`]: ../../std/primitive.slice.html#method.chunks
|
||||
//! [`.windows()`]: ../../std/primitive.slice.html#method.windows
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
// Many of the usings in this module are only used in the test configuration.
|
||||
|
|
@ -168,7 +180,7 @@ impl<T> [T] {
|
|||
core_slice::SliceExt::len(self)
|
||||
}
|
||||
|
||||
/// Returns true if the slice has a length of 0
|
||||
/// Returns true if the slice has a length of 0.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
@ -402,7 +414,7 @@ impl<T> [T] {
|
|||
core_slice::SliceExt::get_unchecked_mut(self, index)
|
||||
}
|
||||
|
||||
/// Returns an raw pointer to the slice's buffer
|
||||
/// Returns an raw pointer to the slice's buffer.
|
||||
///
|
||||
/// The caller must ensure that the slice outlives the pointer this
|
||||
/// function returns, or else it will end up pointing to garbage.
|
||||
|
|
@ -468,7 +480,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut v = ["a", "b", "c", "d"];
|
||||
/// v.swap(1, 3);
|
||||
/// assert!(v == ["a", "d", "c", "b"]);
|
||||
|
|
@ -483,7 +495,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut v = [1, 2, 3];
|
||||
/// v.reverse();
|
||||
/// assert!(v == [3, 2, 1]);
|
||||
|
|
@ -567,9 +579,9 @@ impl<T> [T] {
|
|||
}
|
||||
|
||||
/// Returns an iterator over `size` elements of the slice at a
|
||||
/// time. The chunks are slices and do not overlap. If `size` does not divide the
|
||||
/// length of the slice, then the last chunk will not have length
|
||||
/// `size`.
|
||||
/// time. The chunks are slices and do not overlap. If `size` does
|
||||
/// not divide the length of the slice, then the last chunk will
|
||||
/// not have length `size`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
@ -656,7 +668,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut v = [1, 2, 3, 4, 5, 6];
|
||||
///
|
||||
/// // scoped to restrict the lifetime of the borrows
|
||||
|
|
@ -754,7 +766,7 @@ impl<T> [T] {
|
|||
}
|
||||
|
||||
/// Returns an iterator over subslices separated by elements that match
|
||||
/// `pred`, limited to returning at most `n` items. The matched element is
|
||||
/// `pred`, limited to returning at most `n` items. The matched element is
|
||||
/// not contained in the subslices.
|
||||
///
|
||||
/// The last element returned, if any, will contain the remainder of the
|
||||
|
|
@ -781,7 +793,7 @@ impl<T> [T] {
|
|||
}
|
||||
|
||||
/// Returns an iterator over subslices separated by elements that match
|
||||
/// `pred`, limited to returning at most `n` items. The matched element is
|
||||
/// `pred`, limited to returning at most `n` items. The matched element is
|
||||
/// not contained in the subslices.
|
||||
///
|
||||
/// The last element returned, if any, will contain the remainder of the
|
||||
|
|
@ -835,7 +847,7 @@ impl<T> [T] {
|
|||
|
||||
/// Returns an iterator over subslices separated by elements that match
|
||||
/// `pred` limited to returning at most `n` items. This starts at the end of
|
||||
/// the slice and works backwards. The matched element is not contained in
|
||||
/// the slice and works backwards. The matched element is not contained in
|
||||
/// the subslices.
|
||||
///
|
||||
/// The last element returned, if any, will contain the remainder of the
|
||||
|
|
@ -922,9 +934,9 @@ impl<T> [T] {
|
|||
///
|
||||
/// Looks up a series of four elements. The first is found, with a
|
||||
/// uniquely determined position; the second and third are not
|
||||
/// found; the fourth could match any position in `[1,4]`.
|
||||
/// found; the fourth could match any position in `[1, 4]`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
|
||||
///
|
||||
/// assert_eq!(s.binary_search(&13), Ok(9));
|
||||
|
|
@ -956,9 +968,9 @@ impl<T> [T] {
|
|||
///
|
||||
/// Looks up a series of four elements. The first is found, with a
|
||||
/// uniquely determined position; the second and third are not
|
||||
/// found; the fourth could match any position in `[1,4]`.
|
||||
/// found; the fourth could match any position in `[1, 4]`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
|
||||
///
|
||||
/// let seek = 13;
|
||||
|
|
@ -982,21 +994,23 @@ impl<T> [T] {
|
|||
/// Binary search a sorted slice with a key extraction function.
|
||||
///
|
||||
/// Assumes that the slice is sorted by the key, for instance with
|
||||
/// `sort_by_key` using the same key extraction function.
|
||||
/// [`sort_by_key`] using the same key extraction function.
|
||||
///
|
||||
/// If a matching value is found then returns `Ok`, containing the
|
||||
/// index for the matched element; if no match is found then `Err`
|
||||
/// is returned, containing the index where a matching element could
|
||||
/// be inserted while maintaining sorted order.
|
||||
///
|
||||
/// [`sort_by_key`]: #method.sort_by_key
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Looks up a series of four elements in a slice of pairs sorted by
|
||||
/// their second elements. The first is found, with a uniquely
|
||||
/// determined position; the second and third are not found; the
|
||||
/// fourth could match any position in `[1,4]`.
|
||||
/// fourth could match any position in `[1, 4]`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
|
||||
/// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
|
||||
/// (1, 21), (2, 34), (4, 55)];
|
||||
|
|
@ -1023,7 +1037,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut v = [-5, 4, 1, -3, 2];
|
||||
///
|
||||
/// v.sort();
|
||||
|
|
@ -1037,7 +1051,7 @@ impl<T> [T] {
|
|||
self.sort_by(|a, b| a.cmp(b))
|
||||
}
|
||||
|
||||
/// Sorts the slice, in place, using `key` to extract a key by which to
|
||||
/// Sorts the slice, in place, using `f` to extract a key by which to
|
||||
/// order the sort by.
|
||||
///
|
||||
/// This sort is stable and `O(n log n)` worst-case but allocates
|
||||
|
|
@ -1045,7 +1059,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut v = [-5i32, 4, 1, -3, 2];
|
||||
///
|
||||
/// v.sort_by_key(|k| k.abs());
|
||||
|
|
@ -1067,7 +1081,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut v = [5, 4, 1, 3, 2];
|
||||
/// v.sort_by(|a, b| a.cmp(b));
|
||||
/// assert!(v == [1, 2, 3, 4, 5]);
|
||||
|
|
@ -1094,7 +1108,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut dst = [0, 0, 0];
|
||||
/// let src = [1, 2, 3];
|
||||
///
|
||||
|
|
@ -1116,7 +1130,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let mut dst = [0, 0, 0];
|
||||
/// let src = [1, 2, 3];
|
||||
///
|
||||
|
|
@ -1156,7 +1170,7 @@ impl<T> [T] {
|
|||
/// let x = s.into_vec();
|
||||
/// // `s` cannot be used anymore because it has been converted into `x`.
|
||||
///
|
||||
/// assert_eq!(x, vec!(10, 40, 30));
|
||||
/// assert_eq!(x, vec![10, 40, 30]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub struct EncodeUtf16<'a> {
|
|||
encoder: Utf16Encoder<Chars<'a>>,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "encode_utf16", since = "1.8.0")]
|
||||
impl<'a> Iterator for EncodeUtf16<'a> {
|
||||
type Item = u16;
|
||||
|
||||
|
|
@ -697,7 +697,7 @@ impl str {
|
|||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// let bananas = "bananas";
|
||||
///
|
||||
/// assert!(bananas.ends_with("anas"));
|
||||
|
|
@ -900,7 +900,7 @@ impl str {
|
|||
///
|
||||
/// It does _not_ give you:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```,ignore
|
||||
/// assert_eq!(d, &["a", "b", "c"]);
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -1053,10 +1053,10 @@ impl str {
|
|||
}
|
||||
|
||||
/// An iterator over substrings of the given string slice, separated by a
|
||||
/// pattern, restricted to returning at most `count` items.
|
||||
/// pattern, restricted to returning at most `n` items.
|
||||
///
|
||||
/// The last element returned, if any, will contain the remainder of the
|
||||
/// string slice.
|
||||
/// If `n` substrings are returned, the last substring (the `n`th substring)
|
||||
/// will contain the remainder of the string.
|
||||
///
|
||||
/// The pattern can be a `&str`, [`char`], or a closure that determines the
|
||||
/// split.
|
||||
|
|
@ -1098,16 +1098,16 @@ impl str {
|
|||
/// assert_eq!(v, ["abc", "defXghi"]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
|
||||
core_str::StrExt::splitn(self, count, pat)
|
||||
pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
|
||||
core_str::StrExt::splitn(self, n, pat)
|
||||
}
|
||||
|
||||
/// An iterator over substrings of this string slice, separated by a
|
||||
/// pattern, starting from the end of the string, restricted to returning
|
||||
/// at most `count` items.
|
||||
/// at most `n` items.
|
||||
///
|
||||
/// The last element returned, if any, will contain the remainder of the
|
||||
/// string slice.
|
||||
/// If `n` substrings are returned, the last substring (the `n`th substring)
|
||||
/// will contain the remainder of the string.
|
||||
///
|
||||
/// The pattern can be a `&str`, [`char`], or a closure that
|
||||
/// determines the split.
|
||||
|
|
@ -1145,10 +1145,10 @@ impl str {
|
|||
/// assert_eq!(v, ["ghi", "abc1def"]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
|
||||
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
|
||||
where P::Searcher: ReverseSearcher<'a>
|
||||
{
|
||||
core_str::StrExt::rsplitn(self, count, pat)
|
||||
core_str::StrExt::rsplitn(self, n, pat)
|
||||
}
|
||||
|
||||
/// An iterator over the matches of a pattern within the given string
|
||||
|
|
@ -1789,4 +1789,24 @@ impl str {
|
|||
String::from_utf8_unchecked(slice.into_vec())
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [`String`] by repeating a string `n` times.
|
||||
///
|
||||
/// [`String`]: string/struct.String.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(repeat_str)]
|
||||
///
|
||||
/// assert_eq!("abc".repeat(4), String::from("abcabcabcabc"));
|
||||
/// ```
|
||||
#[unstable(feature = "repeat_str", issue = "37079")]
|
||||
pub fn repeat(&self, n: usize) -> String {
|
||||
let mut s = String::with_capacity(self.len() * n);
|
||||
s.extend((0..n).map(|_| self));
|
||||
s
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,24 +14,25 @@
|
|||
//! [`ToString`]s, and several error types that may result from working with
|
||||
//! [`String`]s.
|
||||
//!
|
||||
//! [`String`]: struct.String.html
|
||||
//! [`ToString`]: trait.ToString.html
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! There are multiple ways to create a new `String` from a string literal:
|
||||
//! There are multiple ways to create a new [`String`] from a string literal:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```
|
||||
//! let s = "Hello".to_string();
|
||||
//!
|
||||
//! let s = String::from("world");
|
||||
//! let s: String = "also this".into();
|
||||
//! ```
|
||||
//!
|
||||
//! You can create a new `String` from an existing one by concatenating with
|
||||
//! You can create a new [`String`] from an existing one by concatenating with
|
||||
//! `+`:
|
||||
//!
|
||||
//! ```rust
|
||||
//! [`String`]: struct.String.html
|
||||
//!
|
||||
//! ```
|
||||
//! let s = "Hello".to_string();
|
||||
//!
|
||||
//! let message = s + " world!";
|
||||
|
|
@ -40,7 +41,7 @@
|
|||
//! If you have a vector of valid UTF-8 bytes, you can make a `String` out of
|
||||
//! it. You can do the reverse too.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```
|
||||
//! let sparkle_heart = vec![240, 159, 146, 150];
|
||||
//!
|
||||
//! // We know these bytes are valid, so we'll use `unwrap()`.
|
||||
|
|
@ -134,10 +135,10 @@ use boxed::Box;
|
|||
/// Indexing is intended to be a constant-time operation, but UTF-8 encoding
|
||||
/// does not allow us to do this. Furthermore, it's not clear what sort of
|
||||
/// thing the index should return: a byte, a codepoint, or a grapheme cluster.
|
||||
/// The [`as_bytes()`] and [`chars()`] methods return iterators over the first
|
||||
/// The [`bytes()`] and [`chars()`] methods return iterators over the first
|
||||
/// two, respectively.
|
||||
///
|
||||
/// [`as_bytes()`]: #method.as_bytes
|
||||
/// [`bytes()`]: #method.bytes
|
||||
/// [`chars()`]: #method.chars
|
||||
///
|
||||
/// # Deref
|
||||
|
|
@ -975,7 +976,7 @@ impl String {
|
|||
pub fn push(&mut self, ch: char) {
|
||||
match ch.len_utf8() {
|
||||
1 => self.vec.push(ch as u8),
|
||||
_ => self.vec.extend_from_slice(ch.encode_utf8().as_slice()),
|
||||
_ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1131,10 +1132,11 @@ impl String {
|
|||
let len = self.len();
|
||||
assert!(idx <= len);
|
||||
assert!(self.is_char_boundary(idx));
|
||||
let bits = ch.encode_utf8();
|
||||
let mut bits = [0; 4];
|
||||
let bits = ch.encode_utf8(&mut bits).as_bytes();
|
||||
|
||||
unsafe {
|
||||
self.insert_bytes(idx, bits.as_slice());
|
||||
self.insert_bytes(idx, bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1858,6 +1860,13 @@ impl<'a> From<&'a str> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "string_from_cow_str", since = "1.14.0")]
|
||||
impl<'a> From<Cow<'a, str>> for String {
|
||||
fn from(s: Cow<'a, str>) -> String {
|
||||
s.into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> From<&'a str> for Cow<'a, str> {
|
||||
#[inline]
|
||||
|
|
@ -1902,26 +1911,6 @@ impl Into<Vec<u8>> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "stringfromchars", since = "1.12.0")]
|
||||
impl<'a> From<&'a [char]> for String {
|
||||
#[inline]
|
||||
fn from(v: &'a [char]) -> String {
|
||||
let mut s = String::with_capacity(v.len());
|
||||
for c in v {
|
||||
s.push(*c);
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "stringfromchars", since = "1.12.0")]
|
||||
impl From<Vec<char>> for String {
|
||||
#[inline]
|
||||
fn from(v: Vec<char>) -> String {
|
||||
String::from(v.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Write for String {
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@
|
|||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! You can explicitly create a `Vec<T>` with `new()`:
|
||||
//! You can explicitly create a [`Vec<T>`] with [`new()`]:
|
||||
//!
|
||||
//! ```
|
||||
//! let v: Vec<i32> = Vec::new();
|
||||
//! ```
|
||||
//!
|
||||
//! ...or by using the `vec!` macro:
|
||||
//! ...or by using the [`vec!`] macro:
|
||||
//!
|
||||
//! ```
|
||||
//! let v: Vec<i32> = vec![];
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
//! let v = vec![0; 10]; // ten zeroes
|
||||
//! ```
|
||||
//!
|
||||
//! You can `push` values onto the end of a vector (which will grow the vector
|
||||
//! You can [`push`] values onto the end of a vector (which will grow the vector
|
||||
//! as needed):
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -49,13 +49,20 @@
|
|||
//! let two = v.pop();
|
||||
//! ```
|
||||
//!
|
||||
//! Vectors also support indexing (through the `Index` and `IndexMut` traits):
|
||||
//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits):
|
||||
//!
|
||||
//! ```
|
||||
//! let mut v = vec![1, 2, 3];
|
||||
//! let three = v[2];
|
||||
//! v[1] = v[1] + 5;
|
||||
//! ```
|
||||
//!
|
||||
//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
//! [`new()`]: ../../std/vec/struct.Vec.html#method.new
|
||||
//! [`push`]: ../../std/vec/struct.Vec.html#method.push
|
||||
//! [`Index`]: ../../std/ops/trait.Index.html
|
||||
//! [`IndexMut`]: ../../std/ops/trait.IndexMut.html
|
||||
//! [`vec!`]: ../../std/macro.vec.html
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -79,7 +86,7 @@ use core::slice;
|
|||
use super::SpecExtend;
|
||||
use super::range::RangeArgument;
|
||||
|
||||
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector.'
|
||||
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -105,7 +112,7 @@ use super::range::RangeArgument;
|
|||
/// assert_eq!(vec, [7, 1, 2, 3]);
|
||||
/// ```
|
||||
///
|
||||
/// The `vec!` macro is provided to make initialization more convenient:
|
||||
/// The [`vec!`] macro is provided to make initialization more convenient:
|
||||
///
|
||||
/// ```
|
||||
/// let mut vec = vec![1, 2, 3];
|
||||
|
|
@ -137,19 +144,19 @@ use super::range::RangeArgument;
|
|||
///
|
||||
/// # Indexing
|
||||
///
|
||||
/// The Vec type allows to access values by index, because it implements the
|
||||
/// `Index` trait. An example will be more explicit:
|
||||
/// The `Vec` type allows to access values by index, because it implements the
|
||||
/// [`Index`] trait. An example will be more explicit:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec!(0, 2, 4, 6);
|
||||
/// let v = vec![0, 2, 4, 6];
|
||||
/// println!("{}", v[1]); // it will display '2'
|
||||
/// ```
|
||||
///
|
||||
/// However be careful: if you try to access an index which isn't in the Vec,
|
||||
/// However be careful: if you try to access an index which isn't in the `Vec`,
|
||||
/// your software will panic! You cannot do this:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let v = vec!(0, 2, 4, 6);
|
||||
/// let v = vec![0, 2, 4, 6];
|
||||
/// println!("{}", v[6]); // it will panic!
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -158,15 +165,15 @@ use super::range::RangeArgument;
|
|||
///
|
||||
/// # Slicing
|
||||
///
|
||||
/// A Vec can be mutable. Slices, on the other hand, are read-only objects.
|
||||
/// To get a slice, use "&". Example:
|
||||
/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects.
|
||||
/// To get a slice, use `&`. Example:
|
||||
///
|
||||
/// ```
|
||||
/// fn read_slice(slice: &[usize]) {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// let v = vec!(0, 1);
|
||||
/// let v = vec![0, 1];
|
||||
/// read_slice(&v);
|
||||
///
|
||||
/// // ... and that's all!
|
||||
|
|
@ -175,8 +182,8 @@ use super::range::RangeArgument;
|
|||
/// ```
|
||||
///
|
||||
/// In Rust, it's more common to pass slices as arguments rather than vectors
|
||||
/// when you just want to provide a read access. The same goes for String and
|
||||
/// &str.
|
||||
/// when you just want to provide a read access. The same goes for [`String`] and
|
||||
/// [`&str`].
|
||||
///
|
||||
/// # Capacity and reallocation
|
||||
///
|
||||
|
|
@ -191,84 +198,100 @@ use super::range::RangeArgument;
|
|||
/// with space for 10 more elements. Pushing 10 or fewer elements onto the
|
||||
/// vector will not change its capacity or cause reallocation to occur. However,
|
||||
/// if the vector's length is increased to 11, it will have to reallocate, which
|
||||
/// can be slow. For this reason, it is recommended to use `Vec::with_capacity`
|
||||
/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`]
|
||||
/// whenever possible to specify how big the vector is expected to get.
|
||||
///
|
||||
/// # Guarantees
|
||||
///
|
||||
/// Due to its incredibly fundamental nature, Vec makes a lot of guarantees
|
||||
/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees
|
||||
/// about its design. This ensures that it's as low-overhead as possible in
|
||||
/// the general case, and can be correctly manipulated in primitive ways
|
||||
/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
|
||||
/// If additional type parameters are added (e.g. to support custom allocators),
|
||||
/// overriding their defaults may change the behavior.
|
||||
///
|
||||
/// Most fundamentally, Vec is and always will be a (pointer, capacity, length)
|
||||
/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length)
|
||||
/// triplet. No more, no less. The order of these fields is completely
|
||||
/// unspecified, and you should use the appropriate methods to modify these.
|
||||
/// The pointer will never be null, so this type is null-pointer-optimized.
|
||||
///
|
||||
/// However, the pointer may not actually point to allocated memory. In particular,
|
||||
/// if you construct a Vec with capacity 0 via `Vec::new()`, `vec![]`,
|
||||
/// `Vec::with_capacity(0)`, or by calling `shrink_to_fit()` on an empty Vec, it
|
||||
/// will not allocate memory. Similarly, if you store zero-sized types inside
|
||||
/// a Vec, it will not allocate space for them. *Note that in this case the
|
||||
/// Vec may not report a `capacity()` of 0*. Vec will allocate if and only
|
||||
/// if `mem::size_of::<T>() * capacity() > 0`. In general, Vec's allocation
|
||||
/// if you construct a `Vec` with capacity 0 via [`Vec::new()`], [`vec![]`][`vec!`],
|
||||
/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit()`]
|
||||
/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
|
||||
/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
|
||||
/// the `Vec` may not report a [`capacity()`] of 0*. `Vec` will allocate if and only
|
||||
/// if [`mem::size_of::<T>()`]` * capacity() > 0`. In general, `Vec`'s allocation
|
||||
/// details are subtle enough that it is strongly recommended that you only
|
||||
/// free memory allocated by a Vec by creating a new Vec and dropping it.
|
||||
/// free memory allocated by a `Vec` by creating a new `Vec` and dropping it.
|
||||
///
|
||||
/// If a Vec *has* allocated memory, then the memory it points to is on the heap
|
||||
/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
|
||||
/// (as defined by the allocator Rust is configured to use by default), and its
|
||||
/// pointer points to `len()` initialized elements in order (what you would see
|
||||
/// if you coerced it to a slice), followed by `capacity() - len()` logically
|
||||
/// uninitialized elements.
|
||||
/// pointer points to [`len()`] initialized elements in order (what you would see
|
||||
/// if you coerced it to a slice), followed by [`capacity()`]` - `[`len()`]
|
||||
/// logically uninitialized elements.
|
||||
///
|
||||
/// Vec will never perform a "small optimization" where elements are actually
|
||||
/// `Vec` will never perform a "small optimization" where elements are actually
|
||||
/// stored on the stack for two reasons:
|
||||
///
|
||||
/// * It would make it more difficult for unsafe code to correctly manipulate
|
||||
/// a Vec. The contents of a Vec wouldn't have a stable address if it were
|
||||
/// only moved, and it would be more difficult to determine if a Vec had
|
||||
/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were
|
||||
/// only moved, and it would be more difficult to determine if a `Vec` had
|
||||
/// actually allocated memory.
|
||||
///
|
||||
/// * It would penalize the general case, incurring an additional branch
|
||||
/// on every access.
|
||||
///
|
||||
/// Vec will never automatically shrink itself, even if completely empty. This
|
||||
/// ensures no unnecessary allocations or deallocations occur. Emptying a Vec
|
||||
/// and then filling it back up to the same `len()` should incur no calls to
|
||||
/// the allocator. If you wish to free up unused memory, use `shrink_to_fit`.
|
||||
/// `Vec` will never automatically shrink itself, even if completely empty. This
|
||||
/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec`
|
||||
/// and then filling it back up to the same [`len()`] should incur no calls to
|
||||
/// the allocator. If you wish to free up unused memory, use
|
||||
/// [`shrink_to_fit`][`shrink_to_fit()`].
|
||||
///
|
||||
/// `push` and `insert` will never (re)allocate if the reported capacity is
|
||||
/// sufficient. `push` and `insert` *will* (re)allocate if `len() == capacity()`.
|
||||
/// That is, the reported capacity is completely accurate, and can be relied on.
|
||||
/// It can even be used to manually free the memory allocated by a Vec if
|
||||
/// desired. Bulk insertion methods *may* reallocate, even when not necessary.
|
||||
/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
|
||||
/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
|
||||
/// [`len()`]` == `[`capacity()`]. That is, the reported capacity is completely
|
||||
/// accurate, and can be relied on. It can even be used to manually free the memory
|
||||
/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
|
||||
/// when not necessary.
|
||||
///
|
||||
/// Vec does not guarantee any particular growth strategy when reallocating
|
||||
/// when full, nor when `reserve` is called. The current strategy is basic
|
||||
/// `Vec` does not guarantee any particular growth strategy when reallocating
|
||||
/// when full, nor when [`reserve`] is called. The current strategy is basic
|
||||
/// and it may prove desirable to use a non-constant growth factor. Whatever
|
||||
/// strategy is used will of course guarantee `O(1)` amortized `push`.
|
||||
/// strategy is used will of course guarantee `O(1)` amortized [`push`].
|
||||
///
|
||||
/// `vec![x; n]`, `vec![a, b, c, d]`, and `Vec::with_capacity(n)`, will all
|
||||
/// produce a Vec with exactly the requested capacity. If `len() == capacity()`,
|
||||
/// (as is the case for the `vec!` macro), then a `Vec<T>` can be converted
|
||||
/// to and from a `Box<[T]>` without reallocating or moving the elements.
|
||||
/// `vec![x; n]`, `vec![a, b, c, d]`, and
|
||||
/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
|
||||
/// with exactly the requested capacity. If [`len()`]` == `[`capacity()`],
|
||||
/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
|
||||
/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
|
||||
///
|
||||
/// Vec will not specifically overwrite any data that is removed from it,
|
||||
/// `Vec` will not specifically overwrite any data that is removed from it,
|
||||
/// but also won't specifically preserve it. Its uninitialized memory is
|
||||
/// scratch space that it may use however it wants. It will generally just do
|
||||
/// whatever is most efficient or otherwise easy to implement. Do not rely on
|
||||
/// removed data to be erased for security purposes. Even if you drop a Vec, its
|
||||
/// buffer may simply be reused by another Vec. Even if you zero a Vec's memory
|
||||
/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
|
||||
/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
|
||||
/// first, that may not actually happen because the optimizer does not consider
|
||||
/// this a side-effect that must be preserved.
|
||||
///
|
||||
/// Vec does not currently guarantee the order in which elements are dropped
|
||||
/// `Vec` does not currently guarantee the order in which elements are dropped
|
||||
/// (the order has changed in the past, and may change again).
|
||||
///
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
/// [`vec!`]: ../../std/macro.vec.html
|
||||
/// [`Index`]: ../../std/ops/trait.Index.html
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`&str`]: ../../std/primitive.str.html
|
||||
/// [`Vec::with_capacity`]: ../../std/vec/struct.Vec.html#method.with_capacity
|
||||
/// [`Vec::new()`]: ../../std/vec/struct.Vec.html#method.new
|
||||
/// [`shrink_to_fit()`]: ../../std/vec/struct.Vec.html#method.shrink_to_fit
|
||||
/// [`capacity()`]: ../../std/vec/struct.Vec.html#method.capacity
|
||||
/// [`mem::size_of::<T>()`]: ../../std/mem/fn.size_of.html
|
||||
/// [`len()`]: ../../std/vec/struct.Vec.html#method.len
|
||||
/// [`push`]: ../../std/vec/struct.Vec.html#method.push
|
||||
/// [`insert`]: ../../std/vec/struct.Vec.html#method.insert
|
||||
/// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve
|
||||
/// [owned slice]: ../../std/boxed/struct.Box.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Vec<T> {
|
||||
buf: RawVec<T>,
|
||||
|
|
@ -305,9 +328,10 @@ impl<T> Vec<T> {
|
|||
/// reallocating. If `capacity` is 0, the vector will not allocate.
|
||||
///
|
||||
/// It is important to note that this function does not specify the *length*
|
||||
/// of the returned vector, but only the *capacity*. (For an explanation of
|
||||
/// the difference between length and capacity, see the main `Vec<T>` docs
|
||||
/// above, 'Capacity and reallocation'.)
|
||||
/// of the returned vector, but only the *capacity*. For an explanation of
|
||||
/// the difference between length and capacity, see *[Capacity and reallocation]*.
|
||||
///
|
||||
/// [Capacity and reallocation]: #capacity-and-reallocation
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -341,7 +365,7 @@ impl<T> Vec<T> {
|
|||
/// This is highly unsafe, due to the number of invariants that aren't
|
||||
/// checked:
|
||||
///
|
||||
/// * `ptr` needs to have been previously allocated via `String`/`Vec<T>`
|
||||
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
|
||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
||||
/// * `length` needs to be less than or equal to `capacity`.
|
||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
|
|
@ -355,6 +379,8 @@ impl<T> Vec<T> {
|
|||
/// that nothing else uses the pointer after calling this
|
||||
/// function.
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -471,11 +497,15 @@ impl<T> Vec<T> {
|
|||
self.buf.shrink_to_fit(self.len);
|
||||
}
|
||||
|
||||
/// Converts the vector into Box<[T]>.
|
||||
/// Converts the vector into [`Box<[T]>`][owned slice].
|
||||
///
|
||||
/// Note that this will drop any excess capacity. Calling this and
|
||||
/// converting back to a vector with `into_vec()` is equivalent to calling
|
||||
/// `shrink_to_fit()`.
|
||||
/// converting back to a vector with [`into_vec()`] is equivalent to calling
|
||||
/// [`shrink_to_fit()`].
|
||||
///
|
||||
/// [owned slice]: ../../std/boxed/struct.Box.html
|
||||
/// [`into_vec()`]: ../../std/primitive.slice.html#method.into_vec
|
||||
/// [`shrink_to_fit()`]: #method.shrink_to_fit
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -674,7 +704,7 @@ impl<T> Vec<T> {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `index` is greater than the vector's length.
|
||||
/// Panics if `index` is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -749,7 +779,7 @@ impl<T> Vec<T> {
|
|||
|
||||
/// Retains only the elements specified by the predicate.
|
||||
///
|
||||
/// In other words, remove all elements `e` such that `f(&e)` returns false.
|
||||
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
|
||||
/// This method operates in place and preserves the order of the retained
|
||||
/// elements.
|
||||
///
|
||||
|
|
@ -782,6 +812,130 @@ impl<T> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Removes consecutive elements in the vector that resolve to the same key.
|
||||
///
|
||||
/// If the vector is sorted, this removes all duplicates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(dedup_by)]
|
||||
///
|
||||
/// let mut vec = vec![10, 20, 21, 30, 20];
|
||||
///
|
||||
/// vec.dedup_by_key(|i| *i / 10);
|
||||
///
|
||||
/// assert_eq!(vec, [10, 20, 30, 20]);
|
||||
/// ```
|
||||
#[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
|
||||
#[inline]
|
||||
pub fn dedup_by_key<F, K>(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq {
|
||||
self.dedup_by(|a, b| key(a) == key(b))
|
||||
}
|
||||
|
||||
/// Removes consecutive elements in the vector that resolve to the same key.
|
||||
///
|
||||
/// If the vector is sorted, this removes all duplicates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(dedup_by)]
|
||||
/// use std::ascii::AsciiExt;
|
||||
///
|
||||
/// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
|
||||
///
|
||||
/// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
|
||||
///
|
||||
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
|
||||
/// ```
|
||||
#[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
|
||||
pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
|
||||
unsafe {
|
||||
// Although we have a mutable reference to `self`, we cannot make
|
||||
// *arbitrary* changes. The `same_bucket` calls could panic, so we
|
||||
// must ensure that the vector is in a valid state at all time.
|
||||
//
|
||||
// The way that we handle this is by using swaps; we iterate
|
||||
// over all the elements, swapping as we go so that at the end
|
||||
// the elements we wish to keep are in the front, and those we
|
||||
// wish to reject are at the back. We can then truncate the
|
||||
// vector. This operation is still O(n).
|
||||
//
|
||||
// Example: We start in this state, where `r` represents "next
|
||||
// read" and `w` represents "next_write`.
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate, so
|
||||
// we swap self[r] and self[w] (no effect as r==w) and then increment both
|
||||
// r and w, leaving us with:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this value is a duplicate,
|
||||
// so we increment `r` but leave everything else unchanged:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate,
|
||||
// so swap self[r] and self[w] and advance r and w:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 1 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Not a duplicate, repeat:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 3 | 1 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Duplicate, advance r. End of vec. Truncate to w.
|
||||
|
||||
let ln = self.len();
|
||||
if ln <= 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid bounds checks by using raw pointers.
|
||||
let p = self.as_mut_ptr();
|
||||
let mut r: usize = 1;
|
||||
let mut w: usize = 1;
|
||||
|
||||
while r < ln {
|
||||
let p_r = p.offset(r as isize);
|
||||
let p_wm1 = p.offset((w - 1) as isize);
|
||||
if !same_bucket(&mut *p_r, &mut *p_wm1) {
|
||||
if r != w {
|
||||
let p_w = p_wm1.offset(1);
|
||||
mem::swap(&mut *p_r, &mut *p_w);
|
||||
}
|
||||
w += 1;
|
||||
}
|
||||
r += 1;
|
||||
}
|
||||
|
||||
self.truncate(w);
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends an element to the back of a collection.
|
||||
///
|
||||
/// # Panics
|
||||
|
|
@ -810,9 +964,11 @@ impl<T> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Removes the last element from a vector and returns it, or `None` if it
|
||||
/// Removes the last element from a vector and returns it, or [`None`] if it
|
||||
/// is empty.
|
||||
///
|
||||
/// [`None`]: ../../std/option/enum.Option.html#variant.None
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -1156,90 +1312,9 @@ impl<T: PartialEq> Vec<T> {
|
|||
/// assert_eq!(vec, [1, 2, 3, 2]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn dedup(&mut self) {
|
||||
unsafe {
|
||||
// Although we have a mutable reference to `self`, we cannot make
|
||||
// *arbitrary* changes. The `PartialEq` comparisons could panic, so we
|
||||
// must ensure that the vector is in a valid state at all time.
|
||||
//
|
||||
// The way that we handle this is by using swaps; we iterate
|
||||
// over all the elements, swapping as we go so that at the end
|
||||
// the elements we wish to keep are in the front, and those we
|
||||
// wish to reject are at the back. We can then truncate the
|
||||
// vector. This operation is still O(n).
|
||||
//
|
||||
// Example: We start in this state, where `r` represents "next
|
||||
// read" and `w` represents "next_write`.
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate, so
|
||||
// we swap self[r] and self[w] (no effect as r==w) and then increment both
|
||||
// r and w, leaving us with:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this value is a duplicate,
|
||||
// so we increment `r` but leave everything else unchanged:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate,
|
||||
// so swap self[r] and self[w] and advance r and w:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 1 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Not a duplicate, repeat:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 3 | 1 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Duplicate, advance r. End of vec. Truncate to w.
|
||||
|
||||
let ln = self.len();
|
||||
if ln <= 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid bounds checks by using raw pointers.
|
||||
let p = self.as_mut_ptr();
|
||||
let mut r: usize = 1;
|
||||
let mut w: usize = 1;
|
||||
|
||||
while r < ln {
|
||||
let p_r = p.offset(r as isize);
|
||||
let p_wm1 = p.offset((w - 1) as isize);
|
||||
if *p_r != *p_wm1 {
|
||||
if r != w {
|
||||
let p_w = p_wm1.offset(1);
|
||||
mem::swap(&mut *p_r, &mut *p_w);
|
||||
}
|
||||
w += 1;
|
||||
}
|
||||
r += 1;
|
||||
}
|
||||
|
||||
self.truncate(w);
|
||||
}
|
||||
self.dedup_by(|a, b| a == b)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1572,7 +1647,24 @@ impl<T> Vec<T> {
|
|||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
|
||||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
<I as SpecExtendVec<T>>::extend_vec(iter, self);
|
||||
}
|
||||
}
|
||||
|
||||
// helper trait for specialization of Vec's Extend impl
|
||||
trait SpecExtendVec<T> {
|
||||
fn extend_vec(self, vec: &mut Vec<T>);
|
||||
}
|
||||
|
||||
impl <'a, T: 'a + Copy, I: IntoIterator<Item=&'a T>> SpecExtendVec<T> for I {
|
||||
default fn extend_vec(self, vec: &mut Vec<T>) {
|
||||
vec.extend(self.into_iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Copy> SpecExtendVec<T> for &'a [T] {
|
||||
fn extend_vec(self, vec: &mut Vec<T>) {
|
||||
vec.extend_from_slice(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1705,6 +1797,13 @@ impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
|
||||
impl<'a, T> From<Cow<'a, [T]>> for Vec<T> where [T]: ToOwned<Owned=Vec<T>> {
|
||||
fn from(s: Cow<'a, [T]>) -> Vec<T> {
|
||||
s.into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> From<&'a str> for Vec<u8> {
|
||||
fn from(s: &'a str) -> Vec<u8> {
|
||||
|
|
@ -1756,7 +1855,7 @@ pub struct IntoIter<T> {
|
|||
end: *const T,
|
||||
}
|
||||
|
||||
#[stable(feature = "vec_intoiter_debug", since = "")]
|
||||
#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IntoIter")
|
||||
|
|
@ -1770,7 +1869,7 @@ impl<T> IntoIter<T> {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// # #![feature(vec_into_iter_as_slice)]
|
||||
/// let vec = vec!['a', 'b', 'c'];
|
||||
/// let mut into_iter = vec.into_iter();
|
||||
|
|
@ -1789,7 +1888,7 @@ impl<T> IntoIter<T> {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// # #![feature(vec_into_iter_as_slice)]
|
||||
/// let vec = vec!['a', 'b', 'c'];
|
||||
/// let mut into_iter = vec.into_iter();
|
||||
|
|
@ -1930,7 +2029,7 @@ unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
|
|||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T> Iterator for Drain<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
|
|
@ -1944,7 +2043,7 @@ impl<'a, T> Iterator for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
|
|
@ -1952,7 +2051,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T> Drop for Drain<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// exhaust self first
|
||||
|
|
@ -1974,7 +2073,7 @@ impl<'a, T> Drop for Drain<'a, T> {
|
|||
}
|
||||
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
|
|||
|
|
@ -726,33 +726,25 @@ impl<T> VecDeque<T> {
|
|||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut vector: VecDeque<u32> = VecDeque::new();
|
||||
/// let mut vector = VecDeque::new();
|
||||
///
|
||||
/// vector.push_back(0);
|
||||
/// vector.push_back(1);
|
||||
/// vector.push_back(2);
|
||||
///
|
||||
/// assert_eq!(vector.as_slices(), (&[0u32, 1, 2] as &[u32], &[] as &[u32]));
|
||||
/// assert_eq!(vector.as_slices(), (&[0, 1, 2][..], &[][..]));
|
||||
///
|
||||
/// vector.push_front(10);
|
||||
/// vector.push_front(9);
|
||||
///
|
||||
/// assert_eq!(vector.as_slices(), (&[9u32, 10] as &[u32], &[0u32, 1, 2] as &[u32]));
|
||||
/// assert_eq!(vector.as_slices(), (&[9, 10][..], &[0, 1, 2][..]));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn as_slices(&self) -> (&[T], &[T]) {
|
||||
unsafe {
|
||||
let contiguous = self.is_contiguous();
|
||||
let buf = self.buffer_as_slice();
|
||||
if contiguous {
|
||||
let (empty, buf) = buf.split_at(0);
|
||||
(&buf[self.tail..self.head], empty)
|
||||
} else {
|
||||
let (mid, right) = buf.split_at(self.tail);
|
||||
let (left, _) = mid.split_at(self.head);
|
||||
(right, left)
|
||||
}
|
||||
RingSlices::ring_slices(buf, self.head, self.tail)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -764,7 +756,7 @@ impl<T> VecDeque<T> {
|
|||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut vector: VecDeque<u32> = VecDeque::new();
|
||||
/// let mut vector = VecDeque::new();
|
||||
///
|
||||
/// vector.push_back(0);
|
||||
/// vector.push_back(1);
|
||||
|
|
@ -774,26 +766,16 @@ impl<T> VecDeque<T> {
|
|||
///
|
||||
/// vector.as_mut_slices().0[0] = 42;
|
||||
/// vector.as_mut_slices().1[0] = 24;
|
||||
/// assert_eq!(vector.as_slices(), (&[42u32, 10] as &[u32], &[24u32, 1] as &[u32]));
|
||||
/// assert_eq!(vector.as_slices(), (&[42, 10][..], &[24, 1][..]));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
|
||||
unsafe {
|
||||
let contiguous = self.is_contiguous();
|
||||
let head = self.head;
|
||||
let tail = self.tail;
|
||||
let buf = self.buffer_as_mut_slice();
|
||||
|
||||
if contiguous {
|
||||
let (empty, buf) = buf.split_at_mut(0);
|
||||
(&mut buf[tail..head], empty)
|
||||
} else {
|
||||
let (mid, right) = buf.split_at_mut(tail);
|
||||
let (left, _) = mid.split_at_mut(head);
|
||||
|
||||
(right, left)
|
||||
}
|
||||
RingSlices::ring_slices(buf, head, tail)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1829,6 +1811,42 @@ fn wrap_index(index: usize, size: usize) -> usize {
|
|||
index & (size - 1)
|
||||
}
|
||||
|
||||
/// Returns the two slices that cover the VecDeque's valid range
|
||||
trait RingSlices : Sized {
|
||||
fn slice(self, from: usize, to: usize) -> Self;
|
||||
fn split_at(self, i: usize) -> (Self, Self);
|
||||
|
||||
fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) {
|
||||
let contiguous = tail <= head;
|
||||
if contiguous {
|
||||
let (empty, buf) = buf.split_at(0);
|
||||
(buf.slice(tail, head), empty)
|
||||
} else {
|
||||
let (mid, right) = buf.split_at(tail);
|
||||
let (left, _) = mid.split_at(head);
|
||||
(right, left)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RingSlices for &'a [T] {
|
||||
fn slice(self, from: usize, to: usize) -> Self {
|
||||
&self[from..to]
|
||||
}
|
||||
fn split_at(self, i: usize) -> (Self, Self) {
|
||||
(*self).split_at(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RingSlices for &'a mut [T] {
|
||||
fn slice(self, from: usize, to: usize) -> Self {
|
||||
&mut self[from..to]
|
||||
}
|
||||
fn split_at(self, i: usize) -> (Self, Self) {
|
||||
(*self).split_at_mut(i)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the number of elements left to be read in the buffer
|
||||
#[inline]
|
||||
fn count(tail: usize, head: usize, size: usize) -> usize {
|
||||
|
|
@ -1875,6 +1893,14 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||
let len = count(self.tail, self.head, self.ring.len());
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
|
||||
accum = front.iter().fold(accum, &mut f);
|
||||
back.iter().fold(accum, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1927,6 +1953,14 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
|||
let len = count(self.tail, self.head, self.ring.len());
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
|
||||
accum = front.iter_mut().fold(accum, &mut f);
|
||||
back.iter_mut().fold(accum, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -2002,7 +2036,7 @@ unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
|
|||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> Drop for Drain<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
for _ in self.by_ref() {}
|
||||
|
|
@ -2051,7 +2085,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> Iterator for Drain<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
|
|
@ -2066,7 +2100,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
|
|
@ -2074,7 +2108,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ fn test_push_unique() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_push_pop() {
|
||||
let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]);
|
||||
assert_eq!(heap.len(), 5);
|
||||
|
|
@ -153,6 +154,7 @@ fn test_push_pop() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_replace() {
|
||||
let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]);
|
||||
assert_eq!(heap.len(), 5);
|
||||
|
|
@ -212,6 +214,7 @@ fn test_empty_peek_mut() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_empty_replace() {
|
||||
let mut heap = BinaryHeap::new();
|
||||
assert!(heap.replace(5).is_none());
|
||||
|
|
@ -296,5 +299,7 @@ fn test_extend_specialization() {
|
|||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
|
||||
d
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -533,9 +533,7 @@ create_append_test!(test_append_1700, 1700);
|
|||
|
||||
fn rand_data(len: usize) -> Vec<(u32, u32)> {
|
||||
let mut rng = DeterministicRng::new();
|
||||
Vec::from_iter(
|
||||
(0..len).map(|_| (rng.next(), rng.next()))
|
||||
)
|
||||
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl DeterministicRng {
|
|||
x: 0x193a6754,
|
||||
y: 0xa8a7d469,
|
||||
z: 0x97830e05,
|
||||
w: 0x113ba7bb
|
||||
w: 0x113ba7bb,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,45 +15,51 @@ use super::DeterministicRng;
|
|||
|
||||
#[test]
|
||||
fn test_clone_eq() {
|
||||
let mut m = BTreeSet::new();
|
||||
let mut m = BTreeSet::new();
|
||||
|
||||
m.insert(1);
|
||||
m.insert(2);
|
||||
m.insert(1);
|
||||
m.insert(2);
|
||||
|
||||
assert!(m.clone() == m);
|
||||
assert!(m.clone() == m);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
let mut x = BTreeSet::new();
|
||||
let mut y = BTreeSet::new();
|
||||
let mut x = BTreeSet::new();
|
||||
let mut y = BTreeSet::new();
|
||||
|
||||
x.insert(1);
|
||||
x.insert(2);
|
||||
x.insert(3);
|
||||
x.insert(1);
|
||||
x.insert(2);
|
||||
x.insert(3);
|
||||
|
||||
y.insert(3);
|
||||
y.insert(2);
|
||||
y.insert(1);
|
||||
y.insert(3);
|
||||
y.insert(2);
|
||||
y.insert(1);
|
||||
|
||||
assert!(::hash(&x) == ::hash(&y));
|
||||
assert!(::hash(&x) == ::hash(&y));
|
||||
}
|
||||
|
||||
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
|
||||
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool,
|
||||
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F)
|
||||
where F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool
|
||||
{
|
||||
let mut set_a = BTreeSet::new();
|
||||
let mut set_b = BTreeSet::new();
|
||||
|
||||
for x in a { assert!(set_a.insert(*x)) }
|
||||
for y in b { assert!(set_b.insert(*y)) }
|
||||
for x in a {
|
||||
assert!(set_a.insert(*x))
|
||||
}
|
||||
for y in b {
|
||||
assert!(set_b.insert(*y))
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
f(&set_a, &set_b, &mut |&x| {
|
||||
assert_eq!(x, expected[i]);
|
||||
i += 1;
|
||||
true
|
||||
});
|
||||
f(&set_a,
|
||||
&set_b,
|
||||
&mut |&x| {
|
||||
assert_eq!(x, expected[i]);
|
||||
i += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
|
|
@ -82,9 +88,7 @@ fn test_difference() {
|
|||
check_difference(&[], &[], &[]);
|
||||
check_difference(&[1, 12], &[], &[1, 12]);
|
||||
check_difference(&[], &[1, 2, 3, 9], &[]);
|
||||
check_difference(&[1, 3, 5, 9, 11],
|
||||
&[3, 9],
|
||||
&[1, 5, 11]);
|
||||
check_difference(&[1, 3, 5, 9, 11], &[3, 9], &[1, 5, 11]);
|
||||
check_difference(&[-5, 11, 22, 33, 40, 42],
|
||||
&[-12, -5, 14, 23, 34, 38, 39, 50],
|
||||
&[11, 22, 33, 40, 42]);
|
||||
|
|
@ -245,10 +249,18 @@ fn test_recovery() {
|
|||
fn test_variance() {
|
||||
use std::collections::btree_set::{IntoIter, Iter, Range};
|
||||
|
||||
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> { v }
|
||||
fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { v }
|
||||
fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { v }
|
||||
fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> { v }
|
||||
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
|
||||
v
|
||||
}
|
||||
fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> {
|
||||
v
|
||||
}
|
||||
fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> {
|
||||
v
|
||||
}
|
||||
fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> {
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -277,9 +289,7 @@ fn test_append() {
|
|||
|
||||
fn rand_data(len: usize) -> Vec<u32> {
|
||||
let mut rng = DeterministicRng::new();
|
||||
Vec::from_iter(
|
||||
(0..len).map(|_| rng.next())
|
||||
)
|
||||
Vec::from_iter((0..len).map(|_| rng.next()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
65
src/libcollectionstest/cow_str.rs
Normal file
65
src/libcollectionstest/cow_str.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2012-2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
// check that Cow<'a, str> implements addition
|
||||
#[test]
|
||||
fn check_cow_add() {
|
||||
borrowed1 = Cow::Borrowed("Hello, ");
|
||||
borrowed2 = Cow::Borrowed("World!");
|
||||
borrow_empty = Cow::Borrowed("");
|
||||
|
||||
owned1 = Cow::Owned("Hi, ".into());
|
||||
owned2 = Cow::Owned("Rustaceans!".into());
|
||||
owned_empty = Cow::Owned("".into());
|
||||
|
||||
assert_eq!("Hello, World!", borrowed1 + borrowed2);
|
||||
assert_eq!("Hello, Rustaceans!", borrowed1 + owned2);
|
||||
|
||||
assert_eq!("Hello, World!", owned1 + borrowed2);
|
||||
assert_eq!("Hello, Rustaceans!", owned1 + owned2);
|
||||
|
||||
if let Cow::Owned(_) = borrowed1 + borrow_empty {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = borrow_empty + borrowed1 {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = borrowed1 + owned_empty {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = owned_empty + borrowed1 {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_cow_add_assign() {
|
||||
borrowed1 = Cow::Borrowed("Hello, ");
|
||||
borrowed2 = Cow::Borrowed("World!");
|
||||
borrow_empty = Cow::Borrowed("");
|
||||
|
||||
owned1 = Cow::Owned("Hi, ".into());
|
||||
owned2 = Cow::Owned("Rustaceans!".into());
|
||||
owned_empty = Cow::Owned("".into());
|
||||
|
||||
let borrowed1clone = borrowed1.clone();
|
||||
borrowed1clone += borrow_empty;
|
||||
assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
|
||||
|
||||
borrowed1clone += owned_empty;
|
||||
assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr());
|
||||
|
||||
owned1 += borrowed2;
|
||||
borrowed1 += owned2;
|
||||
|
||||
assert_eq!("Hello, World!", owned1);
|
||||
assert_eq!("Hello, Rustaceans!", borrowed1);
|
||||
}
|
||||
|
|
@ -16,9 +16,11 @@
|
|||
#![feature(collections)]
|
||||
#![feature(collections_bound)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(dedup_by)]
|
||||
#![feature(enumset)]
|
||||
#![feature(pattern)]
|
||||
#![feature(rand)]
|
||||
#![feature(repeat_str)]
|
||||
#![feature(step_by)]
|
||||
#![feature(str_escape)]
|
||||
#![feature(str_replacen)]
|
||||
|
|
@ -31,9 +33,12 @@ extern crate collections;
|
|||
extern crate test;
|
||||
extern crate rustc_unicode;
|
||||
|
||||
use std::hash::{Hash, Hasher, SipHasher};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
||||
#[cfg(test)] #[macro_use] mod bench;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
mod bench;
|
||||
|
||||
mod binary_heap;
|
||||
mod btree;
|
||||
|
|
@ -47,7 +52,7 @@ mod vec_deque;
|
|||
mod vec;
|
||||
|
||||
fn hash<T: Hash>(t: &T) -> u64 {
|
||||
let mut s = SipHasher::new();
|
||||
let mut s = DefaultHasher::new();
|
||||
t.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,47 +315,6 @@ fn test_clear() {
|
|||
// If the unsafe block didn't drop things properly, we blow up here.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup() {
|
||||
fn case(a: Vec<i32>, b: Vec<i32>) {
|
||||
let mut v = a;
|
||||
v.dedup();
|
||||
assert_eq!(v, b);
|
||||
}
|
||||
case(vec![], vec![]);
|
||||
case(vec![1], vec![1]);
|
||||
case(vec![1, 1], vec![1]);
|
||||
case(vec![1, 2, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 1, 2, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 2, 2, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 2, 3, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup_unique() {
|
||||
let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
|
||||
v0.dedup();
|
||||
let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
|
||||
v1.dedup();
|
||||
let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
|
||||
v2.dedup();
|
||||
// If the boxed pointers were leaked or otherwise misused, valgrind
|
||||
// and/or rt should raise errors.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup_shared() {
|
||||
let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
|
||||
v0.dedup();
|
||||
let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
|
||||
v1.dedup();
|
||||
let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
|
||||
v2.dedup();
|
||||
// If the pointers were leaked or otherwise misused, valgrind and/or
|
||||
// rt should raise errors.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_retain() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
|
|
@ -461,12 +420,12 @@ fn test_sort_stability() {
|
|||
// number this element is, i.e. the second elements
|
||||
// will occur in sorted order.
|
||||
let mut v: Vec<_> = (0..len)
|
||||
.map(|_| {
|
||||
let n = thread_rng().gen::<usize>() % 10;
|
||||
counts[n] += 1;
|
||||
(n, counts[n])
|
||||
})
|
||||
.collect();
|
||||
.map(|_| {
|
||||
let n = thread_rng().gen::<usize>() % 10;
|
||||
counts[n] += 1;
|
||||
(n, counts[n])
|
||||
})
|
||||
.collect();
|
||||
|
||||
// only sort on the first element, so an unstable sort
|
||||
// may mix up the counts.
|
||||
|
|
@ -1116,6 +1075,7 @@ fn test_box_slice_clone() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
fn test_box_slice_clone_panics() {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
|
@ -1156,13 +1116,13 @@ fn test_box_slice_clone_panics() {
|
|||
};
|
||||
|
||||
spawn(move || {
|
||||
// When xs is dropped, +5.
|
||||
let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary]
|
||||
.into_boxed_slice();
|
||||
// When xs is dropped, +5.
|
||||
let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary]
|
||||
.into_boxed_slice();
|
||||
|
||||
// When panic is cloned, +3.
|
||||
xs.clone();
|
||||
})
|
||||
// When panic is cloned, +3.
|
||||
xs.clone();
|
||||
})
|
||||
.join()
|
||||
.unwrap_err();
|
||||
|
||||
|
|
@ -1414,8 +1374,8 @@ mod bench {
|
|||
let mut rng = thread_rng();
|
||||
b.iter(|| {
|
||||
let mut v = rng.gen_iter::<BigSortable>()
|
||||
.take(5)
|
||||
.collect::<Vec<BigSortable>>();
|
||||
.take(5)
|
||||
.collect::<Vec<BigSortable>>();
|
||||
v.sort();
|
||||
});
|
||||
b.bytes = 5 * mem::size_of::<BigSortable>() as u64;
|
||||
|
|
@ -1426,8 +1386,8 @@ mod bench {
|
|||
let mut rng = thread_rng();
|
||||
b.iter(|| {
|
||||
let mut v = rng.gen_iter::<BigSortable>()
|
||||
.take(100)
|
||||
.collect::<Vec<BigSortable>>();
|
||||
.take(100)
|
||||
.collect::<Vec<BigSortable>>();
|
||||
v.sort();
|
||||
});
|
||||
b.bytes = 100 * mem::size_of::<BigSortable>() as u64;
|
||||
|
|
@ -1438,8 +1398,8 @@ mod bench {
|
|||
let mut rng = thread_rng();
|
||||
b.iter(|| {
|
||||
let mut v = rng.gen_iter::<BigSortable>()
|
||||
.take(10000)
|
||||
.collect::<Vec<BigSortable>>();
|
||||
.take(10000)
|
||||
.collect::<Vec<BigSortable>>();
|
||||
v.sort();
|
||||
});
|
||||
b.bytes = 10000 * mem::size_of::<BigSortable>() as u64;
|
||||
|
|
|
|||
|
|
@ -786,9 +786,9 @@ fn test_rev_iterator() {
|
|||
|
||||
#[test]
|
||||
fn test_chars_decoding() {
|
||||
let mut bytes = [0; 4];
|
||||
for c in (0..0x110000).filter_map(::std::char::from_u32) {
|
||||
let bytes = c.encode_utf8();
|
||||
let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
|
||||
let s = c.encode_utf8(&mut bytes);
|
||||
if Some(c) != s.chars().next() {
|
||||
panic!("character {:x}={} does not decode correctly", c as u32, c);
|
||||
}
|
||||
|
|
@ -797,9 +797,9 @@ fn test_chars_decoding() {
|
|||
|
||||
#[test]
|
||||
fn test_chars_rev_decoding() {
|
||||
let mut bytes = [0; 4];
|
||||
for c in (0..0x110000).filter_map(::std::char::from_u32) {
|
||||
let bytes = c.encode_utf8();
|
||||
let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
|
||||
let s = c.encode_utf8(&mut bytes);
|
||||
if Some(c) != s.chars().rev().next() {
|
||||
panic!("character {:x}={} does not decode correctly", c as u32, c);
|
||||
}
|
||||
|
|
@ -1286,6 +1286,13 @@ fn test_cow_from() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat() {
|
||||
assert_eq!("".repeat(3), "");
|
||||
assert_eq!("abc".repeat(0), "");
|
||||
assert_eq!("α".repeat(3), "ααα");
|
||||
}
|
||||
|
||||
mod pattern {
|
||||
use std::str::pattern::Pattern;
|
||||
use std::str::pattern::{Searcher, ReverseSearcher};
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ fn test_from_str() {
|
|||
assert_eq!(owned.as_ref().map(|s| &**s), Some("string"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_cow_str() {
|
||||
assert_eq!(String::from(Cow::Borrowed("string")), "string");
|
||||
assert_eq!(String::from(Cow::Owned(String::from("string"))), "string");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unsized_to_string() {
|
||||
let s: &str = "abc";
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
use std::iter::{FromIterator, repeat};
|
||||
use std::mem::size_of;
|
||||
|
|
@ -213,6 +214,60 @@ fn test_retain() {
|
|||
assert_eq!(vec, [2, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup() {
|
||||
fn case(a: Vec<i32>, b: Vec<i32>) {
|
||||
let mut v = a;
|
||||
v.dedup();
|
||||
assert_eq!(v, b);
|
||||
}
|
||||
case(vec![], vec![]);
|
||||
case(vec![1], vec![1]);
|
||||
case(vec![1, 1], vec![1]);
|
||||
case(vec![1, 2, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 1, 2, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 2, 2, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 2, 3, 3], vec![1, 2, 3]);
|
||||
case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup_by_key() {
|
||||
fn case(a: Vec<i32>, b: Vec<i32>) {
|
||||
let mut v = a;
|
||||
v.dedup_by_key(|i| *i / 10);
|
||||
assert_eq!(v, b);
|
||||
}
|
||||
case(vec![], vec![]);
|
||||
case(vec![10], vec![10]);
|
||||
case(vec![10, 11], vec![10]);
|
||||
case(vec![10, 20, 30], vec![10, 20, 30]);
|
||||
case(vec![10, 11, 20, 30], vec![10, 20, 30]);
|
||||
case(vec![10, 20, 21, 30], vec![10, 20, 30]);
|
||||
case(vec![10, 20, 30, 31], vec![10, 20, 30]);
|
||||
case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup_by() {
|
||||
let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
|
||||
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
|
||||
|
||||
assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup_unique() {
|
||||
let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
|
||||
v0.dedup();
|
||||
let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
|
||||
v1.dedup();
|
||||
let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
|
||||
v2.dedup();
|
||||
// If the boxed pointers were leaked or otherwise misused, valgrind
|
||||
// and/or rt should raise errors.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_sized_values() {
|
||||
let mut v = Vec::new();
|
||||
|
|
@ -271,22 +326,22 @@ fn test_zip_unzip() {
|
|||
|
||||
#[test]
|
||||
fn test_vec_truncate_drop() {
|
||||
static mut drops: u32 = 0;
|
||||
static mut DROPS: u32 = 0;
|
||||
struct Elem(i32);
|
||||
impl Drop for Elem {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
drops += 1;
|
||||
DROPS += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
|
||||
assert_eq!(unsafe { drops }, 0);
|
||||
assert_eq!(unsafe { DROPS }, 0);
|
||||
v.truncate(3);
|
||||
assert_eq!(unsafe { drops }, 2);
|
||||
assert_eq!(unsafe { DROPS }, 2);
|
||||
v.truncate(0);
|
||||
assert_eq!(unsafe { drops }, 5);
|
||||
assert_eq!(unsafe { DROPS }, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -542,10 +597,22 @@ fn test_cow_from() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_cow() {
|
||||
let borrowed: &[_] = &["borrowed", "(slice)"];
|
||||
let owned = vec!["owned", "(vec)"];
|
||||
assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]);
|
||||
assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
|
||||
fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { i }
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
|
||||
d
|
||||
}
|
||||
fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> {
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
|
|||
|
|
@ -686,21 +686,21 @@ fn test_show() {
|
|||
assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
|
||||
|
||||
let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
assert_eq!(format!("{:?}", ringbuf),
|
||||
"[\"just\", \"one\", \"test\", \"more\"]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop() {
|
||||
static mut drops: i32 = 0;
|
||||
static mut DROPS: i32 = 0;
|
||||
struct Elem;
|
||||
impl Drop for Elem {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
drops += 1;
|
||||
DROPS += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -712,17 +712,17 @@ fn test_drop() {
|
|||
ring.push_front(Elem);
|
||||
drop(ring);
|
||||
|
||||
assert_eq!(unsafe { drops }, 4);
|
||||
assert_eq!(unsafe { DROPS }, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_with_pop() {
|
||||
static mut drops: i32 = 0;
|
||||
static mut DROPS: i32 = 0;
|
||||
struct Elem;
|
||||
impl Drop for Elem {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
drops += 1;
|
||||
DROPS += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -735,20 +735,20 @@ fn test_drop_with_pop() {
|
|||
|
||||
drop(ring.pop_back());
|
||||
drop(ring.pop_front());
|
||||
assert_eq!(unsafe { drops }, 2);
|
||||
assert_eq!(unsafe { DROPS }, 2);
|
||||
|
||||
drop(ring);
|
||||
assert_eq!(unsafe { drops }, 4);
|
||||
assert_eq!(unsafe { DROPS }, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop_clear() {
|
||||
static mut drops: i32 = 0;
|
||||
static mut DROPS: i32 = 0;
|
||||
struct Elem;
|
||||
impl Drop for Elem {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
drops += 1;
|
||||
DROPS += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -759,10 +759,10 @@ fn test_drop_clear() {
|
|||
ring.push_back(Elem);
|
||||
ring.push_front(Elem);
|
||||
ring.clear();
|
||||
assert_eq!(unsafe { drops }, 4);
|
||||
assert_eq!(unsafe { DROPS }, 4);
|
||||
|
||||
drop(ring);
|
||||
assert_eq!(unsafe { drops }, 4);
|
||||
assert_eq!(unsafe { DROPS }, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1003,5 +1003,7 @@ fn test_contains() {
|
|||
|
||||
#[allow(dead_code)]
|
||||
fn assert_covariance() {
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
|
||||
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
|
||||
d
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,13 @@ impl Sources {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let target = env::var("TARGET").expect("TARGET was not set");
|
||||
|
||||
// Emscripten's runtime includes all the builtins
|
||||
if target.contains("emscripten") {
|
||||
return;
|
||||
}
|
||||
|
||||
let cfg = &mut gcc::Config::new();
|
||||
|
||||
if target.contains("msvc") {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(not(stage0), feature(compiler_builtins))]
|
||||
#![feature(compiler_builtins)]
|
||||
#![no_std]
|
||||
#![cfg_attr(not(stage0), compiler_builtins)]
|
||||
#![compiler_builtins]
|
||||
#![unstable(feature = "compiler_builtins_lib",
|
||||
reason = "internal implementation detail of rustc right now",
|
||||
issue = "0")]
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@
|
|||
|
||||
use fmt;
|
||||
use intrinsics;
|
||||
use marker::Reflect;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Any trait
|
||||
|
|
@ -86,7 +85,7 @@ use marker::Reflect;
|
|||
///
|
||||
/// [mod]: index.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Any: Reflect + 'static {
|
||||
pub trait Any: 'static {
|
||||
/// Gets the `TypeId` of `self`.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -112,7 +111,7 @@ pub trait Any: Reflect + 'static {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Reflect + 'static + ?Sized > Any for T {
|
||||
impl<T: 'static + ?Sized > Any for T {
|
||||
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
|
||||
}
|
||||
|
||||
|
|
@ -352,12 +351,10 @@ impl TypeId {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(get_type_id)]
|
||||
///
|
||||
/// use std::any::{Any, TypeId};
|
||||
///
|
||||
/// fn is_string(s: &Any) -> bool {
|
||||
/// TypeId::of::<String>() == s.get_type_id()
|
||||
/// fn is_string<T: ?Sized + Any>(_s: &T) -> bool {
|
||||
/// TypeId::of::<String>() == TypeId::of::<T>()
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
|
|
@ -366,7 +363,7 @@ impl TypeId {
|
|||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
|
||||
pub fn of<T: ?Sized + 'static>() -> TypeId {
|
||||
TypeId {
|
||||
t: unsafe { intrinsics::type_id::<T>() },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ macro_rules! __impl_slice_eq2 {
|
|||
macro_rules! array_impls {
|
||||
($($N:expr)+) => {
|
||||
$(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> AsRef<[T]> for [T; $N] {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[T] {
|
||||
|
|
@ -100,6 +101,7 @@ macro_rules! array_impls {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> AsMut<[T]> for [T; $N] {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [T] {
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@
|
|||
|
||||
use cmp::Ordering;
|
||||
use fmt::{self, Debug, Display};
|
||||
use marker::{PhantomData, Unsize};
|
||||
use marker::Unsize;
|
||||
use ops::{Deref, DerefMut, CoerceUnsized};
|
||||
|
||||
/// A mutable memory location that admits only `Copy` data.
|
||||
|
|
@ -403,40 +403,40 @@ pub enum BorrowState {
|
|||
}
|
||||
|
||||
/// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow).
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
pub struct BorrowError<'a, T: 'a + ?Sized> {
|
||||
marker: PhantomData<&'a RefCell<T>>,
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
pub struct BorrowError {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
impl<'a, T: ?Sized> Debug for BorrowError<'a, T> {
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
impl Debug for BorrowError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("BorrowError").finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
impl<'a, T: ?Sized> Display for BorrowError<'a, T> {
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
impl Display for BorrowError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt("already mutably borrowed", f)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error returned by [`RefCell::try_borrow_mut`](struct.RefCell.html#method.try_borrow_mut).
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
pub struct BorrowMutError<'a, T: 'a + ?Sized> {
|
||||
marker: PhantomData<&'a RefCell<T>>,
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
pub struct BorrowMutError {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
impl<'a, T: ?Sized> Debug for BorrowMutError<'a, T> {
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
impl Debug for BorrowMutError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("BorrowMutError").finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
impl<'a, T: ?Sized> Display for BorrowMutError<'a, T> {
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
impl Display for BorrowMutError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt("already borrowed", f)
|
||||
}
|
||||
|
|
@ -573,8 +573,6 @@ impl<T: ?Sized> RefCell<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_borrow)]
|
||||
///
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// let c = RefCell::new(5);
|
||||
|
|
@ -589,15 +587,15 @@ impl<T: ?Sized> RefCell<T> {
|
|||
/// assert!(c.try_borrow().is_ok());
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
#[inline]
|
||||
pub fn try_borrow(&self) -> Result<Ref<T>, BorrowError<T>> {
|
||||
pub fn try_borrow(&self) -> Result<Ref<T>, BorrowError> {
|
||||
match BorrowRef::new(&self.borrow) {
|
||||
Some(b) => Ok(Ref {
|
||||
value: unsafe { &*self.value.get() },
|
||||
borrow: b,
|
||||
}),
|
||||
None => Err(BorrowError { marker: PhantomData }),
|
||||
None => Err(BorrowError { _private: () }),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -654,8 +652,6 @@ impl<T: ?Sized> RefCell<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(try_borrow)]
|
||||
///
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// let c = RefCell::new(5);
|
||||
|
|
@ -667,15 +663,15 @@ impl<T: ?Sized> RefCell<T> {
|
|||
///
|
||||
/// assert!(c.try_borrow_mut().is_ok());
|
||||
/// ```
|
||||
#[unstable(feature = "try_borrow", issue = "35070")]
|
||||
#[stable(feature = "try_borrow", since = "1.13.0")]
|
||||
#[inline]
|
||||
pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError<T>> {
|
||||
pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError> {
|
||||
match BorrowRefMut::new(&self.borrow) {
|
||||
Some(b) => Ok(RefMut {
|
||||
value: unsafe { &mut *self.value.get() },
|
||||
borrow: b,
|
||||
}),
|
||||
None => Err(BorrowMutError { marker: PhantomData }),
|
||||
None => Err(BorrowMutError { _private: () }),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
use char_private::is_printable;
|
||||
use convert::TryFrom;
|
||||
use fmt;
|
||||
use slice;
|
||||
use iter::FusedIterator;
|
||||
use mem::transmute;
|
||||
|
||||
|
|
@ -327,9 +328,9 @@ pub trait CharExt {
|
|||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn len_utf16(self) -> usize;
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
fn encode_utf8(self) -> EncodeUtf8;
|
||||
fn encode_utf8(self, dst: &mut [u8]) -> &mut str;
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
fn encode_utf16(self) -> EncodeUtf16;
|
||||
fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16];
|
||||
}
|
||||
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
|
|
@ -419,47 +420,59 @@ impl CharExt for char {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn encode_utf8(self) -> EncodeUtf8 {
|
||||
fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
|
||||
let code = self as u32;
|
||||
let mut buf = [0; 4];
|
||||
let pos = if code < MAX_ONE_B {
|
||||
buf[3] = code as u8;
|
||||
3
|
||||
} else if code < MAX_TWO_B {
|
||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
1
|
||||
} else {
|
||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
0
|
||||
};
|
||||
EncodeUtf8 { buf: buf, pos: pos }
|
||||
unsafe {
|
||||
let len =
|
||||
if code < MAX_ONE_B && !dst.is_empty() {
|
||||
*dst.get_unchecked_mut(0) = code as u8;
|
||||
1
|
||||
} else if code < MAX_TWO_B && dst.len() >= 2 {
|
||||
*dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
*dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B && dst.len() >= 3 {
|
||||
*dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
*dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT;
|
||||
3
|
||||
} else if dst.len() >= 4 {
|
||||
*dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
*dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
*dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
|
||||
4
|
||||
} else {
|
||||
panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
|
||||
from_u32_unchecked(code).len_utf8(),
|
||||
code,
|
||||
dst.len())
|
||||
};
|
||||
transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn encode_utf16(self) -> EncodeUtf16 {
|
||||
let mut buf = [0; 2];
|
||||
fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
|
||||
let mut code = self as u32;
|
||||
let pos = if (code & 0xFFFF) == code {
|
||||
// The BMP falls through (assuming non-surrogate, as it should)
|
||||
buf[1] = code as u16;
|
||||
1
|
||||
} else {
|
||||
// Supplementary planes break into surrogates.
|
||||
code -= 0x1_0000;
|
||||
buf[0] = 0xD800 | ((code >> 10) as u16);
|
||||
buf[1] = 0xDC00 | ((code as u16) & 0x3FF);
|
||||
0
|
||||
};
|
||||
EncodeUtf16 { buf: buf, pos: pos }
|
||||
unsafe {
|
||||
if (code & 0xFFFF) == code && !dst.is_empty() {
|
||||
// The BMP falls through (assuming non-surrogate, as it should)
|
||||
*dst.get_unchecked_mut(0) = code as u16;
|
||||
slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
|
||||
} else if dst.len() >= 2 {
|
||||
// Supplementary planes break into surrogates.
|
||||
code -= 0x1_0000;
|
||||
*dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
|
||||
*dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
|
||||
slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
|
||||
} else {
|
||||
panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
|
||||
from_u32_unchecked(code).len_utf16(),
|
||||
code,
|
||||
dst.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -702,88 +715,7 @@ impl ExactSizeIterator for EscapeDebug { }
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl FusedIterator for EscapeDebug {}
|
||||
|
||||
/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
|
||||
/// value.
|
||||
///
|
||||
/// Constructed via the `.encode_utf8()` method on `char`.
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
#[derive(Debug)]
|
||||
pub struct EncodeUtf8 {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl EncodeUtf8 {
|
||||
/// Returns the remaining bytes of this iterator as a slice.
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.buf[self.pos..]
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
impl Iterator for EncodeUtf8 {
|
||||
type Item = u8;
|
||||
|
||||
fn next(&mut self) -> Option<u8> {
|
||||
if self.pos == self.buf.len() {
|
||||
None
|
||||
} else {
|
||||
let ret = Some(self.buf[self.pos]);
|
||||
self.pos += 1;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.as_slice().iter().size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl FusedIterator for EncodeUtf8 {}
|
||||
|
||||
/// An iterator over `u16` entries represending the UTF-16 encoding of a `char`
|
||||
/// value.
|
||||
///
|
||||
/// Constructed via the `.encode_utf16()` method on `char`.
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
#[derive(Debug)]
|
||||
pub struct EncodeUtf16 {
|
||||
buf: [u16; 2],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl EncodeUtf16 {
|
||||
/// Returns the remaining bytes of this iterator as a slice.
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
pub fn as_slice(&self) -> &[u16] {
|
||||
&self.buf[self.pos..]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[unstable(feature = "unicode", issue = "27784")]
|
||||
impl Iterator for EncodeUtf16 {
|
||||
type Item = u16;
|
||||
|
||||
fn next(&mut self) -> Option<u16> {
|
||||
if self.pos == self.buf.len() {
|
||||
None
|
||||
} else {
|
||||
let ret = Some(self.buf[self.pos]);
|
||||
self.pos += 1;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.as_slice().iter().size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl FusedIterator for EncodeUtf16 {}
|
||||
|
||||
/// An iterator over an iterator of bytes of the characters the bytes represent
|
||||
/// as UTF-8
|
||||
|
|
@ -800,7 +732,7 @@ pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter>
|
|||
|
||||
/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence.
|
||||
#[unstable(feature = "decode_utf8", issue = "33906")]
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct InvalidSequence(());
|
||||
|
||||
#[unstable(feature = "decode_utf8", issue = "33906")]
|
||||
|
|
|
|||
|
|
@ -129,13 +129,6 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData
|
|||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized> Clone for &'a T {
|
||||
|
|
|
|||
|
|
@ -10,10 +10,13 @@
|
|||
|
||||
//! Functionality for ordering and comparison.
|
||||
//!
|
||||
//! This module defines both `PartialOrd` and `PartialEq` traits which are used
|
||||
//! This module defines both [`PartialOrd`] and [`PartialEq`] traits which are used
|
||||
//! by the compiler to implement comparison operators. Rust programs may
|
||||
//! implement `PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators,
|
||||
//! and may implement `PartialEq` to overload the `==` and `!=` operators.
|
||||
//! implement [`PartialOrd`] to overload the `<`, `<=`, `>`, and `>=` operators,
|
||||
//! and may implement [`PartialEq`] to overload the `==` and `!=` operators.
|
||||
//!
|
||||
//! [`PartialOrd`]: trait.PartialOrd.html
|
||||
//! [`PartialEq`]: trait.PartialEq.html
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
|
|
@ -777,24 +780,24 @@ mod impls {
|
|||
|
||||
ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[unstable(feature = "never_type_impls", issue = "35121")]
|
||||
impl PartialEq for ! {
|
||||
fn eq(&self, _: &!) -> bool {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[unstable(feature = "never_type_impls", issue = "35121")]
|
||||
impl Eq for ! {}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[unstable(feature = "never_type_impls", issue = "35121")]
|
||||
impl PartialOrd for ! {
|
||||
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[unstable(feature = "never_type_impls", issue = "35121")]
|
||||
impl Ord for ! {
|
||||
fn cmp(&self, _: &!) -> Ordering {
|
||||
*self
|
||||
|
|
|
|||
|
|
@ -92,6 +92,22 @@ pub trait AsRef<T: ?Sized> {
|
|||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`Box<T>`] implements `AsMut<T>`:
|
||||
///
|
||||
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
///
|
||||
/// ```
|
||||
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
|
||||
/// *num.as_mut() += 1;
|
||||
/// }
|
||||
///
|
||||
/// let mut boxed_num = Box::new(0);
|
||||
/// add_one(&mut boxed_num);
|
||||
/// assert_eq!(*boxed_num, 1);
|
||||
/// ```
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
|
||||
|
|
|
|||
|
|
@ -97,9 +97,7 @@ pub trait Write {
|
|||
/// This function will return an instance of `Error` on error.
|
||||
#[stable(feature = "fmt_write_char", since = "1.1.0")]
|
||||
fn write_char(&mut self, c: char) -> Result {
|
||||
self.write_str(unsafe {
|
||||
str::from_utf8_unchecked(c.encode_utf8().as_slice())
|
||||
})
|
||||
self.write_str(c.encode_utf8(&mut [0; 4]))
|
||||
}
|
||||
|
||||
/// Glue for usage of the `write!` macro with implementors of this trait.
|
||||
|
|
@ -272,10 +270,14 @@ impl<'a> Arguments<'a> {
|
|||
/// safely be done so, so no constructors are given and the fields are private
|
||||
/// to prevent modification.
|
||||
///
|
||||
/// The `format_args!` macro will safely create an instance of this structure
|
||||
/// The [`format_args!`] macro will safely create an instance of this structure
|
||||
/// and pass it to a function or closure, passed as the first argument. The
|
||||
/// macro validates the format string at compile-time so usage of the `write`
|
||||
/// and `format` functions can be safely performed.
|
||||
/// macro validates the format string at compile-time so usage of the [`write`]
|
||||
/// and [`format`] functions can be safely performed.
|
||||
///
|
||||
/// [`format_args!`]: ../../std/macro.format_args.html
|
||||
/// [`format`]: ../../std/fmt/fn.format.html
|
||||
/// [`write`]: ../../std/fmt/fn.write.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Arguments<'a> {
|
||||
|
|
@ -792,7 +794,7 @@ pub trait UpperExp {
|
|||
/// assert_eq!(output, "Hello world!");
|
||||
/// ```
|
||||
///
|
||||
/// Please note that using [`write!`][write_macro] might be preferrable. Example:
|
||||
/// Please note that using [`write!`] might be preferrable. Example:
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt::Write;
|
||||
|
|
@ -803,7 +805,7 @@ pub trait UpperExp {
|
|||
/// assert_eq!(output, "Hello world!");
|
||||
/// ```
|
||||
///
|
||||
/// [write_macro]: ../../std/macro.write!.html
|
||||
/// [`write!`]: ../../std/macro.write.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn write(output: &mut Write, args: Arguments) -> Result {
|
||||
let mut formatter = Formatter {
|
||||
|
|
@ -920,9 +922,7 @@ impl<'a> Formatter<'a> {
|
|||
// Writes the sign if it exists, and then the prefix if it was requested
|
||||
let write_prefix = |f: &mut Formatter| {
|
||||
if let Some(c) = sign {
|
||||
f.buf.write_str(unsafe {
|
||||
str::from_utf8_unchecked(c.encode_utf8().as_slice())
|
||||
})?;
|
||||
f.buf.write_str(c.encode_utf8(&mut [0; 4]))?;
|
||||
}
|
||||
if prefixed { f.buf.write_str(prefix) }
|
||||
else { Ok(()) }
|
||||
|
|
@ -1028,10 +1028,8 @@ impl<'a> Formatter<'a> {
|
|||
rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
|
||||
};
|
||||
|
||||
let fill = self.fill.encode_utf8();
|
||||
let fill = unsafe {
|
||||
str::from_utf8_unchecked(fill.as_slice())
|
||||
};
|
||||
let mut fill = [0; 4];
|
||||
let fill = self.fill.encode_utf8(&mut fill);
|
||||
|
||||
for _ in 0..pre_pad {
|
||||
self.buf.write_str(fill)?;
|
||||
|
|
@ -1358,14 +1356,14 @@ macro_rules! fmt_refs {
|
|||
|
||||
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[unstable(feature = "never_type_impls", issue = "35121")]
|
||||
impl Debug for ! {
|
||||
fn fmt(&self, _: &mut Formatter) -> Result {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "never_type", issue = "35121")]
|
||||
#[unstable(feature = "never_type_impls", issue = "35121")]
|
||||
impl Display for ! {
|
||||
fn fmt(&self, _: &mut Formatter) -> Result {
|
||||
*self
|
||||
|
|
@ -1431,9 +1429,7 @@ impl Display for char {
|
|||
if f.width.is_none() && f.precision.is_none() {
|
||||
f.write_char(*self)
|
||||
} else {
|
||||
f.pad(unsafe {
|
||||
str::from_utf8_unchecked(self.encode_utf8().as_slice())
|
||||
})
|
||||
f.pad(self.encode_utf8(&mut [0; 4]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1570,11 +1566,11 @@ floating! { f64 }
|
|||
// Implementation of Display/Debug for various core types
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Debug for *const T {
|
||||
impl<T: ?Sized> Debug for *const T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Debug for *mut T {
|
||||
impl<T: ?Sized> Debug for *mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub struct FormatSpec {
|
|||
}
|
||||
|
||||
/// Possible alignments that can be requested as part of a formatting directive.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Alignment {
|
||||
/// Indication that contents should be left-aligned.
|
||||
Left,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@
|
|||
//! ```
|
||||
//!
|
||||
//! If you need more control over how a value is hashed, you need to implement
|
||||
//! the `Hash` trait:
|
||||
//! the [`Hash`] trait:
|
||||
//!
|
||||
//! [`Hash`]: trait.Hash.html
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::hash::{Hash, Hasher, SipHasher};
|
||||
|
|
@ -76,9 +78,11 @@ use marker;
|
|||
use mem;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(deprecated)]
|
||||
pub use self::sip::SipHasher;
|
||||
|
||||
#[unstable(feature = "sip_hash_13", issue = "29754")]
|
||||
#[allow(deprecated)]
|
||||
pub use self::sip::{SipHasher13, SipHasher24};
|
||||
|
||||
mod sip;
|
||||
|
|
@ -88,7 +92,7 @@ mod sip;
|
|||
/// The `H` type parameter is an abstract hash state that is used by the `Hash`
|
||||
/// to compute the hash.
|
||||
///
|
||||
/// If you are also implementing `Eq`, there is an additional property that
|
||||
/// If you are also implementing [`Eq`], there is an additional property that
|
||||
/// is important:
|
||||
///
|
||||
/// ```text
|
||||
|
|
@ -96,13 +100,13 @@ mod sip;
|
|||
/// ```
|
||||
///
|
||||
/// In other words, if two keys are equal, their hashes should also be equal.
|
||||
/// `HashMap` and `HashSet` both rely on this behavior.
|
||||
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
|
||||
///
|
||||
/// ## Derivable
|
||||
///
|
||||
/// This trait can be used with `#[derive]` if all fields implement `Hash`.
|
||||
/// When `derive`d, the resulting hash will be the combination of the values
|
||||
/// from calling `.hash()` on each field.
|
||||
/// from calling [`.hash()`] on each field.
|
||||
///
|
||||
/// ## How can I implement `Hash`?
|
||||
///
|
||||
|
|
@ -125,6 +129,11 @@ mod sip;
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`Eq`]: ../../std/cmp/trait.Eq.html
|
||||
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
|
||||
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
|
||||
/// [`.hash()`]: #tymethod.hash
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Hash {
|
||||
/// Feeds this value into the state given, updating the hasher as necessary.
|
||||
|
|
@ -149,35 +158,35 @@ pub trait Hasher {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn finish(&self) -> u64;
|
||||
|
||||
/// Writes some data into this `Hasher`
|
||||
/// Writes some data into this `Hasher`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn write(&mut self, bytes: &[u8]);
|
||||
|
||||
/// Write a single `u8` into this hasher
|
||||
/// Write a single `u8` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_u8(&mut self, i: u8) {
|
||||
self.write(&[i])
|
||||
}
|
||||
/// Write a single `u16` into this hasher.
|
||||
/// Writes a single `u16` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_u16(&mut self, i: u16) {
|
||||
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
|
||||
}
|
||||
/// Write a single `u32` into this hasher.
|
||||
/// Writes a single `u32` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_u32(&mut self, i: u32) {
|
||||
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
|
||||
}
|
||||
/// Write a single `u64` into this hasher.
|
||||
/// Writes a single `u64` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
|
||||
}
|
||||
/// Write a single `usize` into this hasher.
|
||||
/// Writes a single `usize` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
|
|
@ -187,31 +196,31 @@ pub trait Hasher {
|
|||
self.write(bytes);
|
||||
}
|
||||
|
||||
/// Write a single `i8` into this hasher.
|
||||
/// Writes a single `i8` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_i8(&mut self, i: i8) {
|
||||
self.write_u8(i as u8)
|
||||
}
|
||||
/// Write a single `i16` into this hasher.
|
||||
/// Writes a single `i16` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_i16(&mut self, i: i16) {
|
||||
self.write_u16(i as u16)
|
||||
}
|
||||
/// Write a single `i32` into this hasher.
|
||||
/// Writes a single `i32` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_i32(&mut self, i: i32) {
|
||||
self.write_u32(i as u32)
|
||||
}
|
||||
/// Write a single `i64` into this hasher.
|
||||
/// Writes a single `i64` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_i64(&mut self, i: i64) {
|
||||
self.write_u64(i as u64)
|
||||
}
|
||||
/// Write a single `isize` into this hasher.
|
||||
/// Writes a single `isize` into this hasher.
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_isize(&mut self, i: isize) {
|
||||
|
|
|
|||
|
|
@ -10,13 +10,21 @@
|
|||
|
||||
//! An implementation of SipHash.
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use marker::PhantomData;
|
||||
use ptr;
|
||||
use cmp;
|
||||
use mem;
|
||||
|
||||
/// An implementation of SipHash 1-3.
|
||||
///
|
||||
/// This is currently the default hashing function used by standard library
|
||||
/// (eg. `collections::HashMap` uses it by default).
|
||||
///
|
||||
/// See: https://131002.net/siphash/
|
||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SipHasher13 {
|
||||
hasher: Hasher<Sip13Rounds>,
|
||||
|
|
@ -26,6 +34,7 @@ pub struct SipHasher13 {
|
|||
///
|
||||
/// See: https://131002.net/siphash/
|
||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SipHasher24 {
|
||||
hasher: Hasher<Sip24Rounds>,
|
||||
|
|
@ -35,9 +44,6 @@ pub struct SipHasher24 {
|
|||
///
|
||||
/// See: https://131002.net/siphash/
|
||||
///
|
||||
/// This is currently the default hashing function used by standard library
|
||||
/// (eg. `collections::HashMap` uses it by default).
|
||||
///
|
||||
/// SipHash is a general-purpose hashing function: it runs at a good
|
||||
/// speed (competitive with Spooky and City) and permits strong _keyed_
|
||||
/// hashing. This lets you key your hashtables from a strong RNG, such as
|
||||
|
|
@ -47,6 +53,7 @@ pub struct SipHasher24 {
|
|||
/// it is not intended for cryptographic purposes. As such, all
|
||||
/// cryptographic uses of this implementation are _strongly discouraged_.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SipHasher(SipHasher24);
|
||||
|
||||
|
|
@ -73,69 +80,67 @@ struct State {
|
|||
v3: u64,
|
||||
}
|
||||
|
||||
// sadly, these macro definitions can't appear later,
|
||||
// because they're needed in the following defs;
|
||||
// this design could be improved.
|
||||
|
||||
macro_rules! u8to64_le {
|
||||
($buf:expr, $i:expr) =>
|
||||
($buf[0+$i] as u64 |
|
||||
($buf[1+$i] as u64) << 8 |
|
||||
($buf[2+$i] as u64) << 16 |
|
||||
($buf[3+$i] as u64) << 24 |
|
||||
($buf[4+$i] as u64) << 32 |
|
||||
($buf[5+$i] as u64) << 40 |
|
||||
($buf[6+$i] as u64) << 48 |
|
||||
($buf[7+$i] as u64) << 56);
|
||||
($buf:expr, $i:expr, $len:expr) =>
|
||||
({
|
||||
let mut t = 0;
|
||||
let mut out = 0;
|
||||
while t < $len {
|
||||
out |= ($buf[t+$i] as u64) << t*8;
|
||||
t += 1;
|
||||
}
|
||||
out
|
||||
});
|
||||
}
|
||||
|
||||
/// Load a full u64 word from a byte stream, in LE order. Use
|
||||
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
|
||||
/// to load u64 from a possibly unaligned address.
|
||||
///
|
||||
/// Unsafe because: unchecked indexing at i..i+8
|
||||
#[inline]
|
||||
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
|
||||
debug_assert!(i + 8 <= buf.len());
|
||||
let mut data = 0u64;
|
||||
ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
|
||||
data.to_le()
|
||||
}
|
||||
|
||||
macro_rules! rotl {
|
||||
($x:expr, $b:expr) =>
|
||||
(($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
|
||||
}
|
||||
|
||||
macro_rules! compress {
|
||||
($state:expr) => ({
|
||||
compress!($state.v0, $state.v1, $state.v2, $state.v3)
|
||||
});
|
||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
|
||||
({
|
||||
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
|
||||
$v0 = rotl!($v0, 32);
|
||||
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
|
||||
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
|
||||
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
|
||||
$v2 = rotl!($v2, 32);
|
||||
$v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
|
||||
$v0 = $v0.rotate_left(32);
|
||||
$v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
|
||||
$v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
|
||||
$v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
|
||||
$v2 = $v2.rotate_left(32);
|
||||
});
|
||||
}
|
||||
|
||||
/// Load an integer of the desired type from a byte stream, in LE order. Uses
|
||||
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
|
||||
/// to load it from a possibly unaligned address.
|
||||
///
|
||||
/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
|
||||
macro_rules! load_int_le {
|
||||
($buf:expr, $i:expr, $int_ty:ident) =>
|
||||
({
|
||||
debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
|
||||
let mut data = 0 as $int_ty;
|
||||
ptr::copy_nonoverlapping($buf.get_unchecked($i),
|
||||
&mut data as *mut _ as *mut u8,
|
||||
mem::size_of::<$int_ty>());
|
||||
data.to_le()
|
||||
});
|
||||
}
|
||||
|
||||
/// Load an u64 using up to 7 bytes of a byte slice.
|
||||
///
|
||||
/// Unsafe because: unchecked indexing at start..start+len
|
||||
#[inline]
|
||||
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
||||
debug_assert!(len < 8);
|
||||
let mut i = 0; // current byte index (from LSB) in the output u64
|
||||
let mut out = 0;
|
||||
if i + 3 < len {
|
||||
out = load_int_le!(buf, start + i, u32) as u64;
|
||||
i += 4;
|
||||
}
|
||||
if i + 1 < len {
|
||||
out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
|
||||
i += 2
|
||||
}
|
||||
if i < len {
|
||||
out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
|
||||
i += 1;
|
||||
}
|
||||
debug_assert_eq!(i, len);
|
||||
out
|
||||
}
|
||||
|
||||
impl SipHasher {
|
||||
/// Creates a new `SipHasher` with the two initial keys set to 0.
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
pub fn new() -> SipHasher {
|
||||
SipHasher::new_with_keys(0, 0)
|
||||
}
|
||||
|
|
@ -143,16 +148,17 @@ impl SipHasher {
|
|||
/// Creates a `SipHasher` that is keyed off the provided keys.
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
|
||||
SipHasher(SipHasher24::new_with_keys(key0, key1))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl SipHasher13 {
|
||||
/// Creates a new `SipHasher13` with the two initial keys set to 0.
|
||||
#[inline]
|
||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
pub fn new() -> SipHasher13 {
|
||||
SipHasher13::new_with_keys(0, 0)
|
||||
}
|
||||
|
|
@ -160,6 +166,7 @@ impl SipHasher13 {
|
|||
/// Creates a `SipHasher13` that is keyed off the provided keys.
|
||||
#[inline]
|
||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
|
||||
SipHasher13 {
|
||||
hasher: Hasher::new_with_keys(key0, key1)
|
||||
|
|
@ -171,6 +178,7 @@ impl SipHasher24 {
|
|||
/// Creates a new `SipHasher24` with the two initial keys set to 0.
|
||||
#[inline]
|
||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
pub fn new() -> SipHasher24 {
|
||||
SipHasher24::new_with_keys(0, 0)
|
||||
}
|
||||
|
|
@ -178,6 +186,7 @@ impl SipHasher24 {
|
|||
/// Creates a `SipHasher24` that is keyed off the provided keys.
|
||||
#[inline]
|
||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
|
||||
SipHasher24 {
|
||||
hasher: Hasher::new_with_keys(key0, key1)
|
||||
|
|
@ -215,6 +224,37 @@ impl<S: Sip> Hasher<S> {
|
|||
self.state.v3 = self.k1 ^ 0x7465646279746573;
|
||||
self.ntail = 0;
|
||||
}
|
||||
|
||||
// Specialized write function that is only valid for buffers with len <= 8.
|
||||
// It's used to force inlining of write_u8 and write_usize, those would normally be inlined
|
||||
// except for composite types (that includes slices and str hashing because of delimiter).
|
||||
// Without this extra push the compiler is very reluctant to inline delimiter writes,
|
||||
// degrading performance substantially for the most common use cases.
|
||||
#[inline(always)]
|
||||
fn short_write(&mut self, msg: &[u8]) {
|
||||
debug_assert!(msg.len() <= 8);
|
||||
let length = msg.len();
|
||||
self.length += length;
|
||||
|
||||
let needed = 8 - self.ntail;
|
||||
let fill = cmp::min(length, needed);
|
||||
if fill == 8 {
|
||||
self.tail = unsafe { load_int_le!(msg, 0, u64) };
|
||||
} else {
|
||||
self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail);
|
||||
if length < needed {
|
||||
self.ntail += length;
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.state.v3 ^= self.tail;
|
||||
S::c_rounds(&mut self.state);
|
||||
self.state.v0 ^= self.tail;
|
||||
|
||||
// Buffered tail is now flushed, process new input.
|
||||
self.ntail = length - needed;
|
||||
self.tail = unsafe { u8to64_le(msg, needed, self.ntail) };
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -257,6 +297,21 @@ impl super::Hasher for SipHasher24 {
|
|||
}
|
||||
|
||||
impl<S: Sip> super::Hasher for Hasher<S> {
|
||||
// see short_write comment for explanation
|
||||
#[inline]
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
let bytes = unsafe {
|
||||
::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::<usize>())
|
||||
};
|
||||
self.short_write(bytes);
|
||||
}
|
||||
|
||||
// see short_write comment for explanation
|
||||
#[inline]
|
||||
fn write_u8(&mut self, i: u8) {
|
||||
self.short_write(&[i]);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write(&mut self, msg: &[u8]) {
|
||||
let length = msg.len();
|
||||
|
|
@ -266,19 +321,16 @@ impl<S: Sip> super::Hasher for Hasher<S> {
|
|||
|
||||
if self.ntail != 0 {
|
||||
needed = 8 - self.ntail;
|
||||
self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail;
|
||||
if length < needed {
|
||||
self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
|
||||
self.ntail += length;
|
||||
return
|
||||
} else {
|
||||
self.state.v3 ^= self.tail;
|
||||
S::c_rounds(&mut self.state);
|
||||
self.state.v0 ^= self.tail;
|
||||
self.ntail = 0;
|
||||
}
|
||||
|
||||
let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
|
||||
|
||||
self.state.v3 ^= m;
|
||||
S::c_rounds(&mut self.state);
|
||||
self.state.v0 ^= m;
|
||||
|
||||
self.ntail = 0;
|
||||
}
|
||||
|
||||
// Buffered tail is now flushed, process new input.
|
||||
|
|
@ -287,7 +339,7 @@ impl<S: Sip> super::Hasher for Hasher<S> {
|
|||
|
||||
let mut i = needed;
|
||||
while i < len - left {
|
||||
let mi = unsafe { load_u64_le(msg, i) };
|
||||
let mi = unsafe { load_int_le!(msg, i, u64) };
|
||||
|
||||
self.state.v3 ^= mi;
|
||||
S::c_rounds(&mut self.state);
|
||||
|
|
@ -296,7 +348,7 @@ impl<S: Sip> super::Hasher for Hasher<S> {
|
|||
i += 8;
|
||||
}
|
||||
|
||||
self.tail = u8to64_le!(msg, i, left);
|
||||
self.tail = unsafe { u8to64_le(msg, i, left) };
|
||||
self.ntail = left;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,14 +194,12 @@ extern "rust-intrinsic" {
|
|||
/// own, or if it does not enable any significant optimizations.
|
||||
pub fn assume(b: bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
pub fn likely(b: bool) -> bool;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
|
|
@ -596,6 +594,19 @@ extern "rust-intrinsic" {
|
|||
|
||||
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
|
||||
/// bytes of memory starting at `dst` to `val`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// let mut vec = vec![0; 4];
|
||||
/// unsafe {
|
||||
/// let vec_ptr = vec.as_mut_ptr();
|
||||
/// ptr::write_bytes(vec_ptr, b'a', 2);
|
||||
/// }
|
||||
/// assert_eq!(vec, [b'a', b'a', 0, 0]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
|
||||
|
||||
|
|
|
|||
|
|
@ -195,13 +195,9 @@ pub trait Iterator {
|
|||
last
|
||||
}
|
||||
|
||||
/// Consumes the `n` first elements of the iterator, then returns the
|
||||
/// `next()` one.
|
||||
/// Returns the `n`th element of the iterator.
|
||||
///
|
||||
/// This method will evaluate the iterator `n` times, discarding those elements.
|
||||
/// After it does so, it will call [`next()`] and return its value.
|
||||
///
|
||||
/// [`next()`]: #tymethod.next
|
||||
/// Note that all preceding elements will be consumed (i.e. discarded).
|
||||
///
|
||||
/// Like most indexing operations, the count starts from zero, so `nth(0)`
|
||||
/// returns the first value, `nth(1)` the second, and so on.
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ pub struct Cloned<I> {
|
|||
it: I,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
impl<'a, I, T: 'a> Iterator for Cloned<I>
|
||||
where I: Iterator<Item=&'a T>, T: Clone
|
||||
{
|
||||
|
|
@ -399,9 +399,15 @@ impl<'a, I, T: 'a> Iterator for Cloned<I>
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.it.size_hint()
|
||||
}
|
||||
|
||||
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.it.fold(init, move |acc, elt| f(acc, elt.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
|
||||
where I: DoubleEndedIterator<Item=&'a T>, T: Clone
|
||||
{
|
||||
|
|
@ -410,7 +416,7 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[stable(feature = "iter_cloned", since = "1.1.0")]
|
||||
impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
|
||||
where I: ExactSizeIterator<Item=&'a T>, T: Clone
|
||||
{}
|
||||
|
|
@ -420,6 +426,18 @@ impl<'a, I, T: 'a> FusedIterator for Cloned<I>
|
|||
where I: FusedIterator<Item=&'a T>, T: Clone
|
||||
{}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
|
||||
where I: TrustedRandomAccess<Item=&'a T>, T: Clone
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
self.it.get_unchecked(i).clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn may_have_side_effect() -> bool { true }
|
||||
}
|
||||
|
||||
/// An iterator that repeats endlessly.
|
||||
///
|
||||
/// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its
|
||||
|
|
@ -532,6 +550,25 @@ impl<A, B> Iterator for Chain<A, B> where
|
|||
}
|
||||
}
|
||||
|
||||
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
|
||||
where F: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut accum = init;
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Front => {
|
||||
accum = self.a.fold(accum, &mut f);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
match self.state {
|
||||
ChainState::Both | ChainState::Back => {
|
||||
accum = self.b.fold(accum, &mut f);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
accum
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, mut n: usize) -> Option<A::Item> {
|
||||
match self.state {
|
||||
|
|
@ -643,7 +680,9 @@ impl<A, B> FusedIterator for Chain<A, B>
|
|||
pub struct Zip<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
spec: <(A, B) as ZipImplData>::Data,
|
||||
// index and len are only used by the specialized version of zip
|
||||
index: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -685,17 +724,6 @@ trait ZipImpl<A, B> {
|
|||
B: DoubleEndedIterator + ExactSizeIterator;
|
||||
}
|
||||
|
||||
// Zip specialization data members
|
||||
#[doc(hidden)]
|
||||
trait ZipImplData {
|
||||
type Data: 'static + Clone + Default + fmt::Debug;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> ZipImplData for T {
|
||||
default type Data = ();
|
||||
}
|
||||
|
||||
// General Zip impl
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
|
|
@ -706,7 +734,8 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
Zip {
|
||||
a: a,
|
||||
b: b,
|
||||
spec: Default::default(), // unused
|
||||
index: 0, // unused
|
||||
len: 0, // unused
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -759,20 +788,6 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct ZipImplFields {
|
||||
index: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImplData for (A, B)
|
||||
where A: TrustedRandomAccess, B: TrustedRandomAccess
|
||||
{
|
||||
type Data = ZipImplFields;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
where A: TrustedRandomAccess, B: TrustedRandomAccess
|
||||
|
|
@ -782,21 +797,26 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
Zip {
|
||||
a: a,
|
||||
b: b,
|
||||
spec: ZipImplFields {
|
||||
index: 0,
|
||||
len: len,
|
||||
}
|
||||
index: 0,
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(A::Item, B::Item)> {
|
||||
if self.spec.index < self.spec.len {
|
||||
let i = self.spec.index;
|
||||
self.spec.index += 1;
|
||||
if self.index < self.len {
|
||||
let i = self.index;
|
||||
self.index += 1;
|
||||
unsafe {
|
||||
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
|
||||
}
|
||||
} else if A::may_have_side_effect() && self.index < self.a.len() {
|
||||
// match the base implementation's potential side effects
|
||||
unsafe {
|
||||
self.a.get_unchecked(self.index);
|
||||
}
|
||||
self.index += 1;
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -804,7 +824,7 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.spec.len - self.spec.index;
|
||||
let len = self.len - self.index;
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
|
|
@ -813,9 +833,26 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
where A: DoubleEndedIterator + ExactSizeIterator,
|
||||
B: DoubleEndedIterator + ExactSizeIterator
|
||||
{
|
||||
if self.spec.index < self.spec.len {
|
||||
self.spec.len -= 1;
|
||||
let i = self.spec.len;
|
||||
// Adjust a, b to equal length
|
||||
if A::may_have_side_effect() {
|
||||
let sz = self.a.len();
|
||||
if sz > self.len {
|
||||
for _ in 0..sz - cmp::max(self.len, self.index) {
|
||||
self.a.next_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
if B::may_have_side_effect() {
|
||||
let sz = self.b.len();
|
||||
if sz > self.len {
|
||||
for _ in 0..sz - self.len {
|
||||
self.b.next_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.index < self.len {
|
||||
self.len -= 1;
|
||||
let i = self.len;
|
||||
unsafe {
|
||||
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
|
||||
}
|
||||
|
|
@ -838,6 +875,9 @@ unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
|
|||
(self.a.get_unchecked(i), self.b.get_unchecked(i))
|
||||
}
|
||||
|
||||
fn may_have_side_effect() -> bool {
|
||||
A::may_have_side_effect() || B::may_have_side_effect()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
@ -924,6 +964,13 @@ impl<B, I: Iterator, F> Iterator for Map<I, F> where F: FnMut(I::Item) -> B {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
fn fold<Acc, G>(self, init: Acc, mut g: G) -> Acc
|
||||
where G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
let mut f = self.f;
|
||||
self.iter.fold(init, move |acc, elt| g(acc, f(elt)))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -944,6 +991,18 @@ impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
|
|||
impl<B, I: FusedIterator, F> FusedIterator for Map<I, F>
|
||||
where F: FnMut(I::Item) -> B {}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<B, I, F> TrustedRandomAccess for Map<I, F>
|
||||
where I: TrustedRandomAccess,
|
||||
F: FnMut(I::Item) -> B,
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
(self.f)(self.iter.get_unchecked(i))
|
||||
}
|
||||
#[inline]
|
||||
fn may_have_side_effect() -> bool { true }
|
||||
}
|
||||
|
||||
/// An iterator that filters the elements of `iter` with `predicate`.
|
||||
///
|
||||
/// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its
|
||||
|
|
@ -1159,6 +1218,10 @@ unsafe impl<I> TrustedRandomAccess for Enumerate<I>
|
|||
unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) {
|
||||
(self.count + i, self.iter.get_unchecked(i))
|
||||
}
|
||||
|
||||
fn may_have_side_effect() -> bool {
|
||||
I::may_have_side_effect()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
@ -1788,6 +1851,10 @@ unsafe impl<I> TrustedRandomAccess for Fuse<I>
|
|||
unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
|
||||
self.iter.get_unchecked(i)
|
||||
}
|
||||
|
||||
fn may_have_side_effect() -> bool {
|
||||
I::may_have_side_effect()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
|
|
|
|||
|
|
@ -328,7 +328,8 @@ impl<A: Step> ops::RangeInclusive<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[unstable(feature = "step_by", reason = "recent addition",
|
||||
issue = "27741")]
|
||||
impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
|
||||
A: Clone,
|
||||
for<'a> &'a A: Add<&'a A, Output = A>
|
||||
|
|
@ -352,7 +353,8 @@ impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
|
|||
impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>>
|
||||
where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[unstable(feature = "step_by", reason = "recent addition",
|
||||
issue = "27741")]
|
||||
impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> {
|
||||
type Item = A;
|
||||
|
||||
|
|
@ -466,7 +468,11 @@ macro_rules! range_exact_iter_impl {
|
|||
($($t:ty)*) => ($(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ExactSizeIterator for ops::Range<$t> { }
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! range_incl_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "inclusive_range",
|
||||
reason = "recently added, follows RFC",
|
||||
issue = "28237")]
|
||||
|
|
@ -500,9 +506,12 @@ impl<A: Step> Iterator for ops::Range<A> where
|
|||
}
|
||||
}
|
||||
|
||||
// Ranges of u64 and i64 are excluded because they cannot guarantee having
|
||||
// a length <= usize::MAX, which is required by ExactSizeIterator.
|
||||
// These macros generate `ExactSizeIterator` impls for various range types.
|
||||
// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
|
||||
// because they cannot guarantee having a length <= usize::MAX, which is
|
||||
// required by ExactSizeIterator.
|
||||
range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
|
||||
range_incl_exact_iter_impl!(u8 u16 i8 i16);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step + Clone> DoubleEndedIterator for ops::Range<A> where
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
/// # Safety
|
||||
///
|
||||
/// The iterator's .len() and size_hint() must be exact.
|
||||
/// `.len()` must be cheap to call.
|
||||
///
|
||||
/// .get_unchecked() must return distinct mutable references for distinct
|
||||
/// indices (if applicable), and must return a valid reference if index is in
|
||||
|
|
@ -21,5 +22,7 @@
|
|||
#[doc(hidden)]
|
||||
pub unsafe trait TrustedRandomAccess : ExactSizeIterator {
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
|
||||
/// Return `true` if getting an iterator element may have
|
||||
/// side effects. Remember to take inner iterators into account.
|
||||
fn may_have_side_effect() -> bool;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
#![feature(specialization)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(question_mark)]
|
||||
#![cfg_attr(stage0, feature(question_mark))]
|
||||
#![feature(never_type)]
|
||||
#![feature(prelude_import)]
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,44 @@ macro_rules! assert_eq {
|
|||
});
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let a = 3;
|
||||
/// let b = 2;
|
||||
/// assert_ne!(a, b);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.12.0")]
|
||||
macro_rules! assert_ne {
|
||||
($left:expr , $right:expr) => ({
|
||||
match (&$left, &$right) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
panic!("assertion failed: `(left != right)` \
|
||||
(left: `{:?}`, right: `{:?}`)", left_val, right_val)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
($left:expr , $right:expr, $($arg:tt)*) => ({
|
||||
match (&($left), &($right)) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
panic!("assertion failed: `(left != right)` \
|
||||
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val,
|
||||
format_args!($($arg)*))
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Ensure that a boolean expression is `true` at runtime.
|
||||
///
|
||||
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||
|
|
@ -189,9 +227,37 @@ macro_rules! debug_assert_eq {
|
|||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
///
|
||||
/// Unlike `assert_ne!`, `debug_assert_ne!` statements are only enabled in non
|
||||
/// optimized builds by default. An optimized build will omit all
|
||||
/// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the
|
||||
/// compiler. This makes `debug_assert_ne!` useful for checks that are too
|
||||
/// expensive to be present in a release build but may be helpful during
|
||||
/// development.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let a = 3;
|
||||
/// let b = 2;
|
||||
/// debug_assert_ne!(a, b);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.12.0")]
|
||||
macro_rules! debug_assert_ne {
|
||||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Helper macro for reducing boilerplate code for matching `Result` together
|
||||
/// with converting downstream errors.
|
||||
///
|
||||
/// Prefer using `?` syntax to `try!`. `?` is built in to the language and is
|
||||
/// more succinct than `try!`. It is the standard method for error propagation.
|
||||
///
|
||||
/// `try!` matches the given `Result`. In case of the `Ok` variant, the
|
||||
/// expression has the value of the wrapped value.
|
||||
///
|
||||
|
|
@ -443,3 +509,143 @@ macro_rules! unreachable {
|
|||
macro_rules! unimplemented {
|
||||
() => (panic!("not yet implemented"))
|
||||
}
|
||||
|
||||
/// Built-in macros to the compiler itself.
|
||||
///
|
||||
/// These macros do not have any corresponding definition with a `macro_rules!`
|
||||
/// macro, but are documented here. Their implementations can be found hardcoded
|
||||
/// into libsyntax itself.
|
||||
///
|
||||
/// For more information, see documentation for `std`'s macros.
|
||||
#[cfg(dox)]
|
||||
pub mod builtin {
|
||||
/// The core macro for formatted string creation & output.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::format_args!`].
|
||||
///
|
||||
/// [`std::format_args!`]: ../std/macro.format_args.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! format_args { ($fmt:expr, $($args:tt)*) => ({
|
||||
/* compiler built-in */
|
||||
}) }
|
||||
|
||||
/// Inspect an environment variable at compile time.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::env!`].
|
||||
///
|
||||
/// [`std::env!`]: ../std/macro.env.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Optionally inspect an environment variable at compile time.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::option_env!`].
|
||||
///
|
||||
/// [`std::option_env!`]: ../std/macro.option_env.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Concatenate identifiers into one identifier.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::concat_idents!`].
|
||||
///
|
||||
/// [`std::concat_idents!`]: ../std/macro.concat_idents.html
|
||||
#[unstable(feature = "concat_idents_macro", issue = "29599")]
|
||||
#[macro_export]
|
||||
macro_rules! concat_idents {
|
||||
($($e:ident),*) => ({ /* compiler built-in */ })
|
||||
}
|
||||
|
||||
/// Concatenates literals into a static string slice.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::concat!`].
|
||||
///
|
||||
/// [`std::concat!`]: ../std/macro.concat.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// A macro which expands to the line number on which it was invoked.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::line!`].
|
||||
///
|
||||
/// [`std::line!`]: ../std/macro.line.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! line { () => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// A macro which expands to the column number on which it was invoked.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::column!`].
|
||||
///
|
||||
/// [`std::column!`]: ../std/macro.column.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! column { () => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// A macro which expands to the file name from which it was invoked.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::file!`].
|
||||
///
|
||||
/// [`std::file!`]: ../std/macro.file.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! file { () => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// A macro which stringifies its argument.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::stringify!`].
|
||||
///
|
||||
/// [`std::stringify!`]: ../std/macro.stringify.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Includes a utf8-encoded file as a string.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::include_str!`].
|
||||
///
|
||||
/// [`std::include_str!`]: ../std/macro.include_str.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Includes a file as a reference to a byte array.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::include_bytes!`].
|
||||
///
|
||||
/// [`std::include_bytes!`]: ../std/macro.include_bytes.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Expands to a string that represents the current module path.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::module_path!`].
|
||||
///
|
||||
/// [`std::module_path!`]: ../std/macro.module_path.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! module_path { () => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Boolean evaluation of configuration flags.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::cfg!`].
|
||||
///
|
||||
/// [`std::cfg!`]: ../std/macro.cfg.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) }
|
||||
|
||||
/// Parse a file as an expression or an item according to the context.
|
||||
///
|
||||
/// For more information, see the documentation for [`std::include!`].
|
||||
///
|
||||
/// [`std::include!`]: ../std/macro.include.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[macro_export]
|
||||
macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Primitive traits and marker types representing basic 'kinds' of types.
|
||||
//! Primitive traits and types representing basic properties of types.
|
||||
//!
|
||||
//! Rust types can be classified in various useful ways according to
|
||||
//! intrinsic properties of the type. These classifications, often called
|
||||
//! 'kinds', are represented as traits.
|
||||
//! their intrinsic properties. These classifications are represented
|
||||
//! as traits.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -22,7 +22,21 @@ use hash::Hasher;
|
|||
|
||||
/// Types that can be transferred across thread boundaries.
|
||||
///
|
||||
/// This trait is automatically derived when the compiler determines it's appropriate.
|
||||
/// This trait is automatically implemented when the compiler determines it's
|
||||
/// appropriate.
|
||||
///
|
||||
/// An example of a non-`Send` type is the reference-counting pointer
|
||||
/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same
|
||||
/// reference-counted value, they might try to update the reference count at the
|
||||
/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic
|
||||
/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring
|
||||
/// some overhead) and thus is `Send`.
|
||||
///
|
||||
/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details.
|
||||
///
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "send"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||
|
|
@ -38,10 +52,10 @@ impl<T: ?Sized> !Send for *const T { }
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> !Send for *mut T { }
|
||||
|
||||
/// Types with a constant size known at compile-time.
|
||||
/// Types with a constant size known at compile time.
|
||||
///
|
||||
/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax
|
||||
/// `?Sized` can be used to remove this bound if it is not appropriate.
|
||||
/// All type parameters have an implicit bound of `Sized`. The special syntax
|
||||
/// `?Sized` can be used to remove this bound if it's not appropriate.
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
@ -51,6 +65,26 @@ impl<T: ?Sized> !Send for *mut T { }
|
|||
/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
|
||||
/// struct BarUse(Bar<[i32]>); // OK
|
||||
/// ```
|
||||
///
|
||||
/// The one exception is the implicit `Self` type of a trait, which does not
|
||||
/// get an implicit `Sized` bound. This is because a `Sized` bound prevents
|
||||
/// the trait from being used to form a [trait object]:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(unused_variables)]
|
||||
/// trait Foo { }
|
||||
/// trait Bar: Sized { }
|
||||
///
|
||||
/// struct Impl;
|
||||
/// impl Foo for Impl { }
|
||||
/// impl Bar for Impl { }
|
||||
///
|
||||
/// let x: &Foo = &Impl; // OK
|
||||
/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot
|
||||
/// // be made into an object
|
||||
/// ```
|
||||
///
|
||||
/// [trait object]: ../../book/trait-objects.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sized"]
|
||||
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
|
||||
|
|
@ -59,14 +93,27 @@ pub trait Sized {
|
|||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be "unsized" to a dynamically sized type.
|
||||
/// Types that can be "unsized" to a dynamically-sized type.
|
||||
///
|
||||
/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
|
||||
/// `Unsize<fmt::Debug>`.
|
||||
///
|
||||
/// All implementations of `Unsize` are provided automatically by the compiler.
|
||||
///
|
||||
/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow
|
||||
/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized
|
||||
/// types. See the [DST coercion RFC][RFC982] for more details.
|
||||
///
|
||||
/// [coerceunsized]: ../ops/trait.CoerceUnsized.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
#[unstable(feature = "unsize", issue = "27732")]
|
||||
#[lang="unsize"]
|
||||
pub trait Unsize<T: ?Sized> {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
||||
/// Types whose values can be duplicated simply by copying bits.
|
||||
///
|
||||
/// By default, variable bindings have 'move semantics.' In other
|
||||
/// words:
|
||||
|
|
@ -87,7 +134,8 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// However, if a type implements `Copy`, it instead has 'copy semantics':
|
||||
///
|
||||
/// ```
|
||||
/// // we can just derive a `Copy` implementation
|
||||
/// // We can derive a `Copy` implementation. `Clone` is also required, as it's
|
||||
/// // a supertrait of `Copy`.
|
||||
/// #[derive(Debug, Copy, Clone)]
|
||||
/// struct Foo;
|
||||
///
|
||||
|
|
@ -100,13 +148,59 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// println!("{:?}", x); // A-OK!
|
||||
/// ```
|
||||
///
|
||||
/// It's important to note that in these two examples, the only difference is if you are allowed to
|
||||
/// access `x` after the assignment: a move is also a bitwise copy under the hood.
|
||||
/// It's important to note that in these two examples, the only difference is whether you
|
||||
/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move
|
||||
/// can result in bits being copied in memory, although this is sometimes optimized away.
|
||||
///
|
||||
/// ## How can I implement `Copy`?
|
||||
///
|
||||
/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct MyStruct;
|
||||
/// ```
|
||||
///
|
||||
/// You can also implement `Copy` and `Clone` manually:
|
||||
///
|
||||
/// ```
|
||||
/// struct MyStruct;
|
||||
///
|
||||
/// impl Copy for MyStruct { }
|
||||
///
|
||||
/// impl Clone for MyStruct {
|
||||
/// fn clone(&self) -> MyStruct {
|
||||
/// *self
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||
/// bound on type parameters, which isn't always desired.
|
||||
///
|
||||
/// ## What's the difference between `Copy` and `Clone`?
|
||||
///
|
||||
/// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of
|
||||
/// `Copy` is not overloadable; it is always a simple bit-wise copy.
|
||||
///
|
||||
/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can
|
||||
/// provide any type-specific behavior necessary to duplicate values safely. For example,
|
||||
/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string
|
||||
/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the
|
||||
/// pointer, leading to a double free down the line. For this reason, `String` is `Clone`
|
||||
/// but not `Copy`.
|
||||
///
|
||||
/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement
|
||||
/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self`
|
||||
/// (see the example above).
|
||||
///
|
||||
/// [clone]: ../clone/trait.Clone.html
|
||||
/// [string]: ../../std/string/struct.String.html
|
||||
///
|
||||
/// ## When can my type be `Copy`?
|
||||
///
|
||||
/// A type can implement `Copy` if all of its components implement `Copy`. For example, this
|
||||
/// `struct` can be `Copy`:
|
||||
/// struct can be `Copy`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[allow(dead_code)]
|
||||
|
|
@ -116,7 +210,8 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`.
|
||||
/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`.
|
||||
/// By contrast, consider
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
@ -126,57 +221,35 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `PointList` `struct` cannot implement `Copy`, because [`Vec<T>`] is not `Copy`. If we
|
||||
/// The struct `PointList` cannot implement `Copy`, because [`Vec<T>`] is not `Copy`. If we
|
||||
/// attempt to derive a `Copy` implementation, we'll get an error:
|
||||
///
|
||||
/// ```text
|
||||
/// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
|
||||
/// ```
|
||||
///
|
||||
/// ## When can my type _not_ be `Copy`?
|
||||
/// ## When *can't* my type be `Copy`?
|
||||
///
|
||||
/// Some types can't be copied safely. For example, copying `&mut T` would create an aliased
|
||||
/// mutable reference, and copying [`String`] would result in two attempts to free the same buffer.
|
||||
/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s
|
||||
/// buffer, leading to a double free.
|
||||
///
|
||||
/// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's
|
||||
/// managing some resource besides its own [`size_of::<T>()`] bytes.
|
||||
///
|
||||
/// ## What if I derive `Copy` on a type that can't?
|
||||
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a
|
||||
/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get
|
||||
/// [E0205].
|
||||
///
|
||||
/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error.
|
||||
/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204)
|
||||
/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205).
|
||||
/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204
|
||||
/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205
|
||||
///
|
||||
/// ## When should my type be `Copy`?
|
||||
/// ## When *should* my type be `Copy`?
|
||||
///
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing
|
||||
/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future,
|
||||
/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking
|
||||
/// change: that second example would fail to compile if we made `Foo` non-`Copy`.
|
||||
///
|
||||
/// ## Derivable
|
||||
///
|
||||
/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type.
|
||||
///
|
||||
/// ## How can I implement `Copy`?
|
||||
///
|
||||
/// There are two ways to implement `Copy` on your type:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct MyStruct;
|
||||
/// ```
|
||||
///
|
||||
/// and
|
||||
///
|
||||
/// ```
|
||||
/// struct MyStruct;
|
||||
/// impl Copy for MyStruct {}
|
||||
/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } }
|
||||
/// ```
|
||||
///
|
||||
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||
/// bound on type parameters, which isn't always desired.
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. Keep in mind, though,
|
||||
/// that implementing `Copy` is part of the public API of your type. If the type might become
|
||||
/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to
|
||||
/// avoid a breaking API change.
|
||||
///
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
|
|
@ -188,64 +261,74 @@ pub trait Copy : Clone {
|
|||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be safely shared between threads when aliased.
|
||||
/// Types for which it is safe to share references between threads.
|
||||
///
|
||||
/// This trait is automatically implemented when the compiler determines
|
||||
/// it's appropriate.
|
||||
///
|
||||
/// The precise definition is: a type `T` is `Sync` if `&T` is
|
||||
/// thread-safe. In other words, there is no possibility of data races
|
||||
/// when passing `&T` references between threads.
|
||||
/// [`Send`][send]. In other words, if there is no possibility of
|
||||
/// [undefined behavior][ub] (including data races) when passing
|
||||
/// `&T` references between threads.
|
||||
///
|
||||
/// As one would expect, primitive types like [`u8`] and [`f64`] are all
|
||||
/// `Sync`, and so are simple aggregate types containing them (like
|
||||
/// tuples, structs and enums). More instances of basic `Sync` types
|
||||
/// include "immutable" types like `&T` and those with simple
|
||||
/// inherited mutability, such as [`Box<T>`], [`Vec<T>`] and most other
|
||||
/// collection types. (Generic parameters need to be `Sync` for their
|
||||
/// container to be `Sync`.)
|
||||
/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64]
|
||||
/// are all `Sync`, and so are simple aggregate types containing them,
|
||||
/// like tuples, structs and enums. More examples of basic `Sync`
|
||||
/// types include "immutable" types like `&T`, and those with simple
|
||||
/// inherited mutability, such as [`Box<T>`][box], [`Vec<T>`][vec] and
|
||||
/// most other collection types. (Generic parameters need to be `Sync`
|
||||
/// for their container to be `Sync`.)
|
||||
///
|
||||
/// A somewhat surprising consequence of the definition is `&mut T` is
|
||||
/// `Sync` (if `T` is `Sync`) even though it seems that it might
|
||||
/// provide unsynchronized mutation. The trick is a mutable reference
|
||||
/// stored in an aliasable reference (that is, `& &mut T`) becomes
|
||||
/// read-only, as if it were a `& &T`, hence there is no risk of a data
|
||||
/// race.
|
||||
/// A somewhat surprising consequence of the definition is that `&mut T`
|
||||
/// is `Sync` (if `T` is `Sync`) even though it seems like that might
|
||||
/// provide unsynchronized mutation. The trick is that a mutable
|
||||
/// reference behind a shared reference (that is, `& &mut T`)
|
||||
/// becomes read-only, as if it were a `& &T`. Hence there is no risk
|
||||
/// of a data race.
|
||||
///
|
||||
/// Types that are not `Sync` are those that have "interior
|
||||
/// mutability" in a non-thread-safe way, such as [`Cell`] and [`RefCell`]
|
||||
/// in [`std::cell`]. These types allow for mutation of their contents
|
||||
/// even when in an immutable, aliasable slot, e.g. the contents of
|
||||
/// [`&Cell<T>`][`Cell`] can be [`.set`], and do not ensure data races are
|
||||
/// impossible, hence they cannot be `Sync`. A higher level example
|
||||
/// of a non-`Sync` type is the reference counted pointer
|
||||
/// [`std::rc::Rc`][`Rc`], because any reference [`&Rc<T>`][`Rc`] can clone a new
|
||||
/// reference, which modifies the reference counts in a non-atomic
|
||||
/// way.
|
||||
/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell]
|
||||
/// and [`cell::RefCell`][refcell]. These types allow for mutation of
|
||||
/// their contents even through an immutable, shared reference. For
|
||||
/// example the `set` method on `Cell<T>` takes `&self`, so it requires
|
||||
/// only a shared reference `&Cell<T>`. The method performs no
|
||||
/// synchronization, thus `Cell` cannot be `Sync`.
|
||||
///
|
||||
/// Another example of a non-`Sync` type is the reference-counting
|
||||
/// pointer [`rc::Rc`][rc]. Given any reference `&Rc<T>`, you can clone
|
||||
/// a new `Rc<T>`, modifying the reference counts in a non-atomic way.
|
||||
///
|
||||
/// For cases when one does need thread-safe interior mutability,
|
||||
/// types like the atomics in [`std::sync`][`sync`] and [`Mutex`] / [`RwLock`] in
|
||||
/// the [`sync`] crate do ensure that any mutation cannot cause data
|
||||
/// races. Hence these types are `Sync`.
|
||||
/// Rust provides [atomic data types], as well as explicit locking via
|
||||
/// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types
|
||||
/// ensure that any mutation cannot cause data races, hence the types
|
||||
/// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe
|
||||
/// analogue of `Rc`.
|
||||
///
|
||||
/// Any types with interior mutability must also use the [`std::cell::UnsafeCell`]
|
||||
/// wrapper around the value(s) which can be mutated when behind a `&`
|
||||
/// reference; not doing this is undefined behavior (for example,
|
||||
/// [`transmute`]-ing from `&T` to `&mut T` is invalid).
|
||||
/// Any types with interior mutability must also use the
|
||||
/// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which
|
||||
/// can be mutated through a shared reference. Failing to doing this is
|
||||
/// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing
|
||||
/// from `&T` to `&mut T` is invalid.
|
||||
///
|
||||
/// This trait is automatically derived when the compiler determines it's appropriate.
|
||||
/// See [the Nomicon](../../nomicon/send-and-sync.html) for more
|
||||
/// details about `Sync`.
|
||||
///
|
||||
/// [`u8`]: ../../std/primitive.u8.html
|
||||
/// [`f64`]: ../../std/primitive.f64.html
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
/// [`Cell`]: ../../std/cell/struct.Cell.html
|
||||
/// [`RefCell`]: ../../std/cell/struct.RefCell.html
|
||||
/// [`std::cell`]: ../../std/cell/index.html
|
||||
/// [`.set`]: ../../std/cell/struct.Cell.html#method.set
|
||||
/// [`Rc`]: ../../std/rc/struct.Rc.html
|
||||
/// [`sync`]: ../../std/sync/index.html
|
||||
/// [`Mutex`]: ../../std/sync/struct.Mutex.html
|
||||
/// [`RwLock`]: ../../std/sync/struct.RwLock.html
|
||||
/// [`std::cell::UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html
|
||||
/// [`transmute`]: ../../std/mem/fn.transmute.html
|
||||
/// [send]: trait.Send.html
|
||||
/// [u8]: ../../std/primitive.u8.html
|
||||
/// [f64]: ../../std/primitive.f64.html
|
||||
/// [box]: ../../std/boxed/struct.Box.html
|
||||
/// [vec]: ../../std/vec/struct.Vec.html
|
||||
/// [cell]: ../cell/struct.Cell.html
|
||||
/// [refcell]: ../cell/struct.RefCell.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [atomic data types]: ../sync/atomic/index.html
|
||||
/// [mutex]: ../../std/sync/struct.Mutex.html
|
||||
/// [rwlock]: ../../std/sync/struct.RwLock.html
|
||||
/// [unsafecell]: ../cell/struct.UnsafeCell.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [transmute]: ../../std/mem/fn.transmute.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sync"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
|
||||
|
|
@ -314,29 +397,30 @@ macro_rules! impls{
|
|||
)
|
||||
}
|
||||
|
||||
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
|
||||
/// even though it does not. This allows you to inform the compiler about certain safety properties
|
||||
/// of your code.
|
||||
/// Zero-sized type used to mark things that "act like" they own a `T`.
|
||||
///
|
||||
/// For a more in-depth explanation of how to use `PhantomData<T>`, please see [the Nomicon].
|
||||
/// Adding a `PhantomData<T>` field to your type tells the compiler that your
|
||||
/// type acts as though it stores a value of type `T`, even though it doesn't
|
||||
/// really. This information is used when computing certain safety properties.
|
||||
///
|
||||
/// [the Nomicon]: ../../nomicon/phantom-data.html
|
||||
/// For a more in-depth explanation of how to use `PhantomData<T>`, please see
|
||||
/// [the Nomicon](../../nomicon/phantom-data.html).
|
||||
///
|
||||
/// # A ghastly note 👻👻👻
|
||||
///
|
||||
/// Though they both have scary names, `PhantomData<T>` and 'phantom types' are related, but not
|
||||
/// identical. Phantom types are a more general concept that don't require `PhantomData<T>` to
|
||||
/// implement, but `PhantomData<T>` is the most common way to implement them in a correct manner.
|
||||
/// Though they both have scary names, `PhantomData` and 'phantom types' are
|
||||
/// related, but not identical. A phantom type parameter is simply a type
|
||||
/// parameter which is never used. In Rust, this often causes the compiler to
|
||||
/// complain, and the solution is to add a "dummy" use by way of `PhantomData`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ## Unused lifetime parameter
|
||||
/// ## Unused lifetime parameters
|
||||
///
|
||||
/// Perhaps the most common time that `PhantomData` is required is
|
||||
/// with a struct that has an unused lifetime parameter, typically as
|
||||
/// part of some unsafe code. For example, here is a struct `Slice`
|
||||
/// that has two pointers of type `*const T`, presumably pointing into
|
||||
/// an array somewhere:
|
||||
/// Perhaps the most common use case for `PhantomData` is a struct that has an
|
||||
/// unused lifetime parameter, typically as part of some unsafe code. For
|
||||
/// example, here is a struct `Slice` that has two pointers of type `*const T`,
|
||||
/// presumably pointing into an array somewhere:
|
||||
///
|
||||
/// ```ignore
|
||||
/// struct Slice<'a, T> {
|
||||
|
|
@ -350,7 +434,7 @@ macro_rules! impls{
|
|||
/// intent is not expressed in the code, since there are no uses of
|
||||
/// the lifetime `'a` and hence it is not clear what data it applies
|
||||
/// to. We can correct this by telling the compiler to act *as if* the
|
||||
/// `Slice` struct contained a borrowed reference `&'a T`:
|
||||
/// `Slice` struct contained a reference `&'a T`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::marker::PhantomData;
|
||||
|
|
@ -359,29 +443,53 @@ macro_rules! impls{
|
|||
/// struct Slice<'a, T: 'a> {
|
||||
/// start: *const T,
|
||||
/// end: *const T,
|
||||
/// phantom: PhantomData<&'a T>
|
||||
/// phantom: PhantomData<&'a T>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This also in turn requires that we annotate `T:'a`, indicating
|
||||
/// that `T` is a type that can be borrowed for the lifetime `'a`.
|
||||
/// This also in turn requires the annotation `T: 'a`, indicating
|
||||
/// that any references in `T` are valid over the lifetime `'a`.
|
||||
///
|
||||
/// ## Unused type parameters
|
||||
///
|
||||
/// It sometimes happens that there are unused type parameters that
|
||||
/// indicate what type of data a struct is "tied" to, even though that
|
||||
/// data is not actually found in the struct itself. Here is an
|
||||
/// example where this arises when handling external resources over a
|
||||
/// foreign function interface. `PhantomData<T>` can prevent
|
||||
/// mismatches by enforcing types in the method implementations:
|
||||
/// When initializing a `Slice` you simply provide the value
|
||||
/// `PhantomData` for the field `phantom`:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// # trait ResType { fn foo(&self); }
|
||||
/// # use std::marker::PhantomData;
|
||||
/// # struct Slice<'a, T: 'a> {
|
||||
/// # start: *const T,
|
||||
/// # end: *const T,
|
||||
/// # phantom: PhantomData<&'a T>,
|
||||
/// # }
|
||||
/// fn borrow_vec<'a, T>(vec: &'a Vec<T>) -> Slice<'a, T> {
|
||||
/// let ptr = vec.as_ptr();
|
||||
/// Slice {
|
||||
/// start: ptr,
|
||||
/// end: unsafe { ptr.offset(vec.len() as isize) },
|
||||
/// phantom: PhantomData,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Unused type parameters
|
||||
///
|
||||
/// It sometimes happens that you have unused type parameters which
|
||||
/// indicate what type of data a struct is "tied" to, even though that
|
||||
/// data is not actually found in the struct itself. Here is an
|
||||
/// example where this arises with [FFI]. The foreign interface uses
|
||||
/// handles of type `*mut ()` to refer to Rust values of different
|
||||
/// types. We track the Rust type using a phantom type parameter on
|
||||
/// the struct `ExternalResource` which wraps a handle.
|
||||
///
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// # trait ResType { }
|
||||
/// # struct ParamType;
|
||||
/// # mod foreign_lib {
|
||||
/// # pub fn new(_: usize) -> *mut () { 42 as *mut () }
|
||||
/// # pub fn do_stuff(_: *mut (), _: usize) {}
|
||||
/// # pub fn new(_: usize) -> *mut () { 42 as *mut () }
|
||||
/// # pub fn do_stuff(_: *mut (), _: usize) {}
|
||||
/// # }
|
||||
/// # fn convert_params(_: ParamType) -> usize { 42 }
|
||||
/// use std::marker::PhantomData;
|
||||
|
|
@ -408,21 +516,20 @@ macro_rules! impls{
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Indicating ownership
|
||||
/// ## Ownership and the drop check
|
||||
///
|
||||
/// Adding a field of type `PhantomData<T>` also indicates that your
|
||||
/// struct owns data of type `T`. This in turn implies that when your
|
||||
/// struct is dropped, it may in turn drop one or more instances of
|
||||
/// the type `T`, though that may not be apparent from the other
|
||||
/// structure of the type itself. This is commonly necessary if the
|
||||
/// structure is using a raw pointer like `*mut T` whose referent
|
||||
/// may be dropped when the type is dropped, as a `*mut T` is
|
||||
/// otherwise not treated as owned.
|
||||
/// Adding a field of type `PhantomData<T>` indicates that your
|
||||
/// type owns data of type `T`. This in turn implies that when your
|
||||
/// type is dropped, it may drop one or more instances of the type
|
||||
/// `T`. This has bearing on the Rust compiler's [drop check]
|
||||
/// analysis.
|
||||
///
|
||||
/// If your struct does not in fact *own* the data of type `T`, it is
|
||||
/// better to use a reference type, like `PhantomData<&'a T>`
|
||||
/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
|
||||
/// as not to indicate ownership.
|
||||
///
|
||||
/// [drop check]: ../../nomicon/dropck.html
|
||||
#[lang = "phantom_data"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct PhantomData<T:?Sized>;
|
||||
|
|
@ -438,10 +545,13 @@ mod impls {
|
|||
|
||||
/// Types that can be reflected over.
|
||||
///
|
||||
/// This trait is implemented for all types. Its purpose is to ensure
|
||||
/// that when you write a generic function that will employ
|
||||
/// reflection, that must be reflected (no pun intended) in the
|
||||
/// generic bounds of that function. Here is an example:
|
||||
/// By "reflection" we mean use of the [`Any`][any] trait, or related
|
||||
/// machinery such as [`TypeId`][typeid].
|
||||
///
|
||||
/// `Reflect` is implemented for all types. Its purpose is to ensure
|
||||
/// that when you write a generic function that will employ reflection,
|
||||
/// that must be reflected (no pun intended) in the generic bounds of
|
||||
/// that function.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(reflect_marker)]
|
||||
|
|
@ -455,25 +565,29 @@ mod impls {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Without the declaration `T: Reflect`, `foo` would not type check
|
||||
/// (note: as a matter of style, it would be preferable to write
|
||||
/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but
|
||||
/// we use `Reflect` here to show how it works). The `Reflect` bound
|
||||
/// thus serves to alert `foo`'s caller to the fact that `foo` may
|
||||
/// behave differently depending on whether `T = u32` or not. In
|
||||
/// particular, thanks to the `Reflect` bound, callers know that a
|
||||
/// function declared like `fn bar<T>(...)` will always act in
|
||||
/// precisely the same way no matter what type `T` is supplied,
|
||||
/// because there are no bounds declared on `T`. (The ability for a
|
||||
/// caller to reason about what a function may do based solely on what
|
||||
/// generic bounds are declared is often called the ["parametricity
|
||||
/// property"][1].)
|
||||
/// Without the bound `T: Reflect`, `foo` would not typecheck. (As
|
||||
/// a matter of style, it would be preferable to write `T: Any`,
|
||||
/// because `T: Any` implies `T: Reflect` and `T: 'static`, but we
|
||||
/// use `Reflect` here for illustrative purposes.)
|
||||
///
|
||||
/// [1]: http://en.wikipedia.org/wiki/Parametricity
|
||||
/// The `Reflect` bound serves to alert `foo`'s caller to the
|
||||
/// fact that `foo` may behave differently depending on whether
|
||||
/// `T` is `u32` or not. The ability for a caller to reason about what
|
||||
/// a function may do based solely on what generic bounds are declared
|
||||
/// is often called the "[parametricity property][param]". Despite the
|
||||
/// use of `Reflect`, Rust lacks true parametricity because a generic
|
||||
/// function can, at the very least, call [`mem::size_of`][size_of]
|
||||
/// without employing any trait bounds whatsoever.
|
||||
///
|
||||
/// [any]: ../any/trait.Any.html
|
||||
/// [typeid]: ../any/struct.TypeId.html
|
||||
/// [param]: http://en.wikipedia.org/wiki/Parametricity
|
||||
/// [size_of]: ../mem/fn.size_of.html
|
||||
#[rustc_reflect_like]
|
||||
#[unstable(feature = "reflect_marker",
|
||||
reason = "requires RFC and more experience",
|
||||
issue = "27749")]
|
||||
#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
|
||||
#[rustc_on_unimplemented = "`{Self}` does not implement `Any`; \
|
||||
ensure all type parameters are bounded by `Any`"]
|
||||
pub trait Reflect {}
|
||||
|
|
@ -481,4 +595,6 @@ pub trait Reflect {}
|
|||
#[unstable(feature = "reflect_marker",
|
||||
reason = "requires RFC and more experience",
|
||||
issue = "27749")]
|
||||
#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
|
||||
#[allow(deprecated)]
|
||||
impl Reflect for .. { }
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue