mirror of
https://git.proxmox.com/git/rustc
synced 2025-05-01 16:14:07 +00:00
New upstream version 1.14.0+dfsg1
This commit is contained in:
parent
9e0c209edc
commit
c30ab7b35a
@ -89,6 +89,7 @@ build.
|
||||
$ pacman -S git \
|
||||
make \
|
||||
diffutils \
|
||||
tar \
|
||||
mingw-w64-x86_64-python2 \
|
||||
mingw-w64-x86_64-cmake \
|
||||
mingw-w64-x86_64-gcc
|
||||
@ -126,7 +127,7 @@ ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or
|
||||
newer with the C++ tools. Then all you need to do is to kick off rustbuild.
|
||||
|
||||
```
|
||||
python .\src\bootstrap\bootstrap.py
|
||||
python x.py build
|
||||
```
|
||||
|
||||
Currently rustbuild only works with some known versions of Visual Studio. If you
|
||||
@ -136,7 +137,7 @@ by manually calling the appropriate vcvars file before running the bootstrap.
|
||||
|
||||
```
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
|
||||
python .\src\bootstrap\bootstrap.py
|
||||
python x.py build
|
||||
```
|
||||
|
||||
## Building Documentation
|
||||
|
263
RELEASES.md
263
RELEASES.md
@ -1,260 +1,3 @@
|
||||
Version 1.13.0 (2016-11-10)
|
||||
===========================
|
||||
|
||||
Language
|
||||
--------
|
||||
|
||||
* [Stabilize the `?` operator][36995]. `?` is a simple way to propagate
|
||||
errors, like the `try!` macro, described in [RFC 0243].
|
||||
* [Stabilize macros in type position][36014]. Described in [RFC 873].
|
||||
* [Stabilize attributes on statements][36995]. Described in [RFC 0016].
|
||||
* [Fix `#[derive]` for empty tuple structs/variants][35728]
|
||||
* [Fix lifetime rules for 'if' conditions][36029]
|
||||
* [Avoid loading and parsing unconfigured non-inline modules][36482]
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
* [Add the `-C link-arg` argument][36574]
|
||||
* [Remove the old AST-based backend from rustc_trans][35764]
|
||||
* [Don't enable NEON by default on armv7 Linux][35814]
|
||||
* [Fix debug line number info for macro expansions][35238]
|
||||
* [Do not emit "class method" debuginfo for types that are not
|
||||
DICompositeType][36008]
|
||||
* [Warn about multiple conflicting #[repr] hints][34623]
|
||||
* [When sizing DST, don't double-count nested struct prefixes][36351]
|
||||
* [Default RUST_MIN_STACK to 16MiB for now][36505]
|
||||
* [Improve rlib metadata format][36551]. Reduces rlib size significantly.
|
||||
* [Reject macros with empty repetitions to avoid infinite loop][36721]
|
||||
* [Expand macros without recursing to avoid stack overflows][36214]
|
||||
|
||||
Diagnostics
|
||||
-----------
|
||||
|
||||
* [Replace macro backtraces with labeled local uses][35702]
|
||||
* [Improve error message for missplaced doc comments][33922]
|
||||
* [Buffer unix and lock windows to prevent message interleaving][35975]
|
||||
* [Update lifetime errors to specifically note temporaries][36171]
|
||||
* [Special case a few colors for Windows][36178]
|
||||
* [Suggest `use self` when such an import resolves][36289]
|
||||
* [Be more specific when type parameter shadows primitive type][36338]
|
||||
* Many minor improvements
|
||||
|
||||
Compile-time Optimizations
|
||||
--------------------------
|
||||
|
||||
* [Compute and cache HIR hashes at beginning][35854]
|
||||
* [Don't hash types in loan paths][36004]
|
||||
* [Cache projections in trans][35761]
|
||||
* [Optimize the parser's last token handling][36527]
|
||||
* [Only instantiate #[inline] functions in codegen units referencing
|
||||
them][36524]. This leads to big improvements in cases where crates export
|
||||
define many inline functions without using them directly.
|
||||
* [Lazily allocate TypedArena's first chunk][36592]
|
||||
* [Don't allocate during default HashSet creation][36734]
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
* [`checked_abs`]
|
||||
* [`wrapping_abs`]
|
||||
* [`overflowing_abs`]
|
||||
* [`RefCell::try_borrow`]
|
||||
* [`RefCell::try_borrow_mut`]
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
* [Add `assert_ne!` and `debug_assert_ne!`][35074]
|
||||
* [Make `vec_deque::Drain`, `hash_map::Drain`, and `hash_set::Drain`
|
||||
covariant][35354]
|
||||
* [Implement `AsRef<[T]>` for `std::slice::Iter`][35559]
|
||||
* [Implement `Debug` for `std::vec::IntoIter`][35707]
|
||||
* [`CString`: avoid excessive growth just to 0-terminate][35871]
|
||||
* [Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}`][35627]
|
||||
* [Use arc4rand on FreeBSD][35884]
|
||||
* [memrchr: Correct aligned offset computation][35969]
|
||||
* [Improve Demangling of Rust Symbols][36059]
|
||||
* [Use monotonic time in condition variables][35048]
|
||||
* [Implement `Debug` for `std::path::{Components,Iter}`][36101]
|
||||
* [Implement conversion traits for `char`][35755]
|
||||
* [Fix illegal instruction caused by overflow in channel cloning][36104]
|
||||
* [Zero first byte of CString on drop][36264]
|
||||
* [Inherit overflow checks for sum and product][36372]
|
||||
* [Add missing Eq implementations][36423]
|
||||
* [Implement `Debug` for `DirEntry`][36631]
|
||||
* [When `getaddrinfo` returns `EAI_SYSTEM` retrieve actual error from
|
||||
`errno`][36754]
|
||||
* [`SipHasher`] is deprecated. Use [`DefaultHasher`].
|
||||
* [Implement more traits for `std::io::ErrorKind`][35911]
|
||||
* [Optimize BinaryHeap bounds checking][36072]
|
||||
* [Work around pointer aliasing issue in `Vec::extend_from_slice`,
|
||||
`extend_with_element`][36355]
|
||||
* [Fix overflow checking in unsigned pow()][34942]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
|
||||
* This release includes security fixes to both curl and OpenSSL.
|
||||
* [Fix transitive doctests when panic=abort][cargo/3021]
|
||||
* [Add --all-features flag to cargo][cargo/3038]
|
||||
* [Reject path-based dependencies in `cargo package`][cargo/3060]
|
||||
* [Don't parse the home directory more than once][cargo/3078]
|
||||
* [Don't try to generate Cargo.lock on empty workspaces][cargo/3092]
|
||||
* [Update OpenSSL to 1.0.2j][cargo/3121]
|
||||
* [Add license and license_file to cargo metadata output][cargo/3110]
|
||||
* [Make crates-io registry URL optional in config; ignore all changes to
|
||||
source.crates-io][cargo/3089]
|
||||
* [Don't download dependencies from other platforms][cargo/3123]
|
||||
* [Build transitive dev-dependencies when needed][cargo/3125]
|
||||
* [Add support for per-target rustflags in .cargo/config][cargo/3157]
|
||||
* [Avoid updating registry when adding existing deps][cargo/3144]
|
||||
* [Warn about path overrides that won't work][cargo/3136]
|
||||
* [Use workspaces during `cargo install`][cargo/3146]
|
||||
* [Leak mspdbsrv.exe processes on Windows][cargo/3162]
|
||||
* [Add --message-format flag][cargo/3000]
|
||||
* [Pass target environment for rustdoc][cargo/3205]
|
||||
* [Use `CommandExt::exec` for `cargo run` on Unix][cargo/2818]
|
||||
* [Update curl and curl-sys][cargo/3241]
|
||||
* [Call rustdoc test with the correct cfg flags of a package][cargo/3242]
|
||||
|
||||
Tooling
|
||||
-------
|
||||
|
||||
* [rustdoc: Add the `--sysroot` argument][36586]
|
||||
* [rustdoc: Fix a couple of issues with the search results][35655]
|
||||
* [rustdoc: remove the `!` from macro URLs and titles][35234]
|
||||
* [gdb: Fix pretty-printing special-cased Rust types][35585]
|
||||
* [rustdoc: Filter more incorrect methods inherited through Deref][36266]
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
* [Remove unmaintained style guide][35124]
|
||||
* [Add s390x support][36369]
|
||||
* [Initial work at Haiku OS support][36727]
|
||||
* [Add mips-uclibc targets][35734]
|
||||
* [Crate-ify compiler-rt into compiler-builtins][35021]
|
||||
* [Add rustc version info (git hash + date) to dist tarball][36213]
|
||||
* Many documentation improvements
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
* [`SipHasher`] is deprecated. Use [`DefaultHasher`].
|
||||
* [Deny (by default) transmuting from fn item types to pointer-sized
|
||||
types][34923]. Continuing the long transition to zero-sized fn items,
|
||||
per [RFC 401].
|
||||
* [Fix `#[derive]` for empty tuple structs/variants][35728].
|
||||
Part of [RFC 1506].
|
||||
* [Issue deprecation warnings for safe accesses to extern statics][36173]
|
||||
* [Fix lifetime rules for 'if' conditions][36029].
|
||||
* [Inherit overflow checks for sum and product][36372].
|
||||
* [Forbid user-defined macros named "macro_rules"][36730].
|
||||
|
||||
[33922]: https://github.com/rust-lang/rust/pull/33922
|
||||
[34623]: https://github.com/rust-lang/rust/pull/34623
|
||||
[34923]: https://github.com/rust-lang/rust/pull/34923
|
||||
[34942]: https://github.com/rust-lang/rust/pull/34942
|
||||
[34982]: https://github.com/rust-lang/rust/pull/34982
|
||||
[35021]: https://github.com/rust-lang/rust/pull/35021
|
||||
[35048]: https://github.com/rust-lang/rust/pull/35048
|
||||
[35074]: https://github.com/rust-lang/rust/pull/35074
|
||||
[35124]: https://github.com/rust-lang/rust/pull/35124
|
||||
[35234]: https://github.com/rust-lang/rust/pull/35234
|
||||
[35238]: https://github.com/rust-lang/rust/pull/35238
|
||||
[35354]: https://github.com/rust-lang/rust/pull/35354
|
||||
[35559]: https://github.com/rust-lang/rust/pull/35559
|
||||
[35585]: https://github.com/rust-lang/rust/pull/35585
|
||||
[35627]: https://github.com/rust-lang/rust/pull/35627
|
||||
[35655]: https://github.com/rust-lang/rust/pull/35655
|
||||
[35702]: https://github.com/rust-lang/rust/pull/35702
|
||||
[35707]: https://github.com/rust-lang/rust/pull/35707
|
||||
[35728]: https://github.com/rust-lang/rust/pull/35728
|
||||
[35734]: https://github.com/rust-lang/rust/pull/35734
|
||||
[35755]: https://github.com/rust-lang/rust/pull/35755
|
||||
[35761]: https://github.com/rust-lang/rust/pull/35761
|
||||
[35764]: https://github.com/rust-lang/rust/pull/35764
|
||||
[35814]: https://github.com/rust-lang/rust/pull/35814
|
||||
[35854]: https://github.com/rust-lang/rust/pull/35854
|
||||
[35871]: https://github.com/rust-lang/rust/pull/35871
|
||||
[35884]: https://github.com/rust-lang/rust/pull/35884
|
||||
[35911]: https://github.com/rust-lang/rust/pull/35911
|
||||
[35969]: https://github.com/rust-lang/rust/pull/35969
|
||||
[35975]: https://github.com/rust-lang/rust/pull/35975
|
||||
[36004]: https://github.com/rust-lang/rust/pull/36004
|
||||
[36008]: https://github.com/rust-lang/rust/pull/36008
|
||||
[36014]: https://github.com/rust-lang/rust/pull/36014
|
||||
[36029]: https://github.com/rust-lang/rust/pull/36029
|
||||
[36059]: https://github.com/rust-lang/rust/pull/36059
|
||||
[36072]: https://github.com/rust-lang/rust/pull/36072
|
||||
[36101]: https://github.com/rust-lang/rust/pull/36101
|
||||
[36104]: https://github.com/rust-lang/rust/pull/36104
|
||||
[36171]: https://github.com/rust-lang/rust/pull/36171
|
||||
[36173]: https://github.com/rust-lang/rust/pull/36173
|
||||
[36178]: https://github.com/rust-lang/rust/pull/36178
|
||||
[36213]: https://github.com/rust-lang/rust/pull/36213
|
||||
[36214]: https://github.com/rust-lang/rust/pull/36214
|
||||
[36264]: https://github.com/rust-lang/rust/pull/36264
|
||||
[36266]: https://github.com/rust-lang/rust/pull/36266
|
||||
[36289]: https://github.com/rust-lang/rust/pull/36289
|
||||
[36338]: https://github.com/rust-lang/rust/pull/36338
|
||||
[36351]: https://github.com/rust-lang/rust/pull/36351
|
||||
[36355]: https://github.com/rust-lang/rust/pull/36355
|
||||
[36369]: https://github.com/rust-lang/rust/pull/36369
|
||||
[36372]: https://github.com/rust-lang/rust/pull/36372
|
||||
[36423]: https://github.com/rust-lang/rust/pull/36423
|
||||
[36482]: https://github.com/rust-lang/rust/pull/36482
|
||||
[36505]: https://github.com/rust-lang/rust/pull/36505
|
||||
[36524]: https://github.com/rust-lang/rust/pull/36524
|
||||
[36527]: https://github.com/rust-lang/rust/pull/36527
|
||||
[36551]: https://github.com/rust-lang/rust/pull/36551
|
||||
[36574]: https://github.com/rust-lang/rust/pull/36574
|
||||
[36586]: https://github.com/rust-lang/rust/pull/36586
|
||||
[36592]: https://github.com/rust-lang/rust/pull/36592
|
||||
[36631]: https://github.com/rust-lang/rust/pull/36631
|
||||
[36639]: https://github.com/rust-lang/rust/pull/36639
|
||||
[36721]: https://github.com/rust-lang/rust/pull/36721
|
||||
[36727]: https://github.com/rust-lang/rust/pull/36727
|
||||
[36730]: https://github.com/rust-lang/rust/pull/36730
|
||||
[36734]: https://github.com/rust-lang/rust/pull/36734
|
||||
[36754]: https://github.com/rust-lang/rust/pull/36754
|
||||
[36995]: https://github.com/rust-lang/rust/pull/36995
|
||||
[RFC 0016]: https://github.com/rust-lang/rfcs/blob/master/text/0016-more-attributes.md
|
||||
[RFC 0243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md
|
||||
[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md
|
||||
[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
|
||||
[RFC 873]: https://github.com/rust-lang/rfcs/blob/master/text/0873-type-macros.md
|
||||
[cargo/2818]: https://github.com/rust-lang/cargo/pull/2818
|
||||
[cargo/3000]: https://github.com/rust-lang/cargo/pull/3000
|
||||
[cargo/3021]: https://github.com/rust-lang/cargo/pull/3021
|
||||
[cargo/3038]: https://github.com/rust-lang/cargo/pull/3038
|
||||
[cargo/3060]: https://github.com/rust-lang/cargo/pull/3060
|
||||
[cargo/3078]: https://github.com/rust-lang/cargo/pull/3078
|
||||
[cargo/3089]: https://github.com/rust-lang/cargo/pull/3089
|
||||
[cargo/3092]: https://github.com/rust-lang/cargo/pull/3092
|
||||
[cargo/3110]: https://github.com/rust-lang/cargo/pull/3110
|
||||
[cargo/3121]: https://github.com/rust-lang/cargo/pull/3121
|
||||
[cargo/3123]: https://github.com/rust-lang/cargo/pull/3123
|
||||
[cargo/3125]: https://github.com/rust-lang/cargo/pull/3125
|
||||
[cargo/3136]: https://github.com/rust-lang/cargo/pull/3136
|
||||
[cargo/3144]: https://github.com/rust-lang/cargo/pull/3144
|
||||
[cargo/3146]: https://github.com/rust-lang/cargo/pull/3146
|
||||
[cargo/3157]: https://github.com/rust-lang/cargo/pull/3157
|
||||
[cargo/3162]: https://github.com/rust-lang/cargo/pull/3162
|
||||
[cargo/3205]: https://github.com/rust-lang/cargo/pull/3205
|
||||
[cargo/3241]: https://github.com/rust-lang/cargo/pull/3241
|
||||
[cargo/3242]: https://github.com/rust-lang/cargo/pull/3242
|
||||
[rustup]: https://www.rustup.rs
|
||||
[`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs
|
||||
[`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs
|
||||
[`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs
|
||||
[`RefCell::try_borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow
|
||||
[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut
|
||||
[`SipHasher`]: https://doc.rust-lang.org/std/hash/struct.SipHasher.html
|
||||
[`DefaultHasher`]: https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html
|
||||
|
||||
|
||||
Version 1.12.1 (2016-10-20)
|
||||
===========================
|
||||
|
||||
@ -338,7 +81,7 @@ Diagnostics
|
||||
Most common editors supporting Rust have been updated to work with it. It was
|
||||
previously described [on the Rust blog]
|
||||
(https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html).
|
||||
* [In error descriptions, references are now described in plain english,
|
||||
* [In error descriptions, references are now described in plain English,
|
||||
instead of as "&-ptr"]
|
||||
(https://github.com/rust-lang/rust/pull/35611)
|
||||
* [In error type descriptions, unknown numeric types are named `{integer}` or
|
||||
@ -432,7 +175,7 @@ Libraries
|
||||
(https://github.com/rust-lang/rust/pull/34946)
|
||||
* [`hash_map::Entry`, `hash_map::VacantEntry` and `hash_map::OccupiedEntry`
|
||||
implement `Debug`]
|
||||
(https://github.com/rust-lang/rust/pull/34946)
|
||||
(https://github.com/rust-lang/rust/pull/34937)
|
||||
* [`btree_map::Entry`, `btree_map::VacantEntry` and `btree_map::OccupiedEntry`
|
||||
implement `Debug`]
|
||||
(https://github.com/rust-lang/rust/pull/34885)
|
||||
@ -1169,7 +912,7 @@ Cargo
|
||||
Performance
|
||||
-----------
|
||||
|
||||
* [The time complexity of comparing variables for equivalence during type
|
||||
* [The time complexity of comparing variables for equivalence during type
|
||||
unification is reduced from _O_(_n_!) to _O_(_n_)][1.9tu]. This leads
|
||||
to major compilation time improvement in some scenarios.
|
||||
* [`ToString` is specialized for `str`, giving it the same performance
|
||||
|
63
configure
vendored
63
configure
vendored
@ -507,11 +507,16 @@ case $CFG_CPUTYPE in
|
||||
CFG_CPUTYPE=arm
|
||||
;;
|
||||
|
||||
armv7l)
|
||||
armv6l)
|
||||
CFG_CPUTYPE=arm
|
||||
CFG_OSTYPE="${CFG_OSTYPE}eabihf"
|
||||
;;
|
||||
|
||||
armv7l)
|
||||
CFG_CPUTYPE=armv7
|
||||
CFG_OSTYPE="${CFG_OSTYPE}eabihf"
|
||||
;;
|
||||
|
||||
aarch64)
|
||||
CFG_CPUTYPE=aarch64
|
||||
;;
|
||||
@ -610,6 +615,7 @@ opt docs 1 "build standard library documentation"
|
||||
opt compiler-docs 0 "build compiler documentation"
|
||||
opt optimize-tests 1 "build tests with optimizations"
|
||||
opt debuginfo-tests 0 "build tests with debugger metadata"
|
||||
opt quiet-tests 0 "enable quieter output when running tests"
|
||||
opt libcpp 1 "build llvm with libc++ instead of libstdc++ when using clang"
|
||||
opt llvm-assertions 0 "build LLVM with assertions"
|
||||
opt debug-assertions 0 "build with debugging assertions"
|
||||
@ -636,6 +642,7 @@ opt_nosave optimize-llvm 1 "build optimized LLVM"
|
||||
opt_nosave llvm-assertions 0 "build LLVM with assertions"
|
||||
opt_nosave debug-assertions 0 "build with debugging assertions"
|
||||
opt_nosave debuginfo 0 "build with debugger metadata"
|
||||
opt_nosave debuginfo-lines 0 "build with line number debugger metadata"
|
||||
opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill"
|
||||
|
||||
valopt localstatedir "/var/lib" "local state directory"
|
||||
@ -645,7 +652,6 @@ valopt datadir "${CFG_PREFIX}/share" "install data"
|
||||
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
|
||||
valopt llvm-root "" "set LLVM root"
|
||||
valopt python "" "set path to python"
|
||||
valopt nodejs "" "set path to nodejs"
|
||||
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
|
||||
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
|
||||
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
|
||||
@ -654,7 +660,12 @@ valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
|
||||
valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path"
|
||||
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
|
||||
valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
|
||||
valopt musl-root "/usr/local" "MUSL root installation directory"
|
||||
valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)"
|
||||
valopt musl-root-x86_64 "/usr/local" "x86_64-unknown-linux-musl install directory"
|
||||
valopt musl-root-i686 "/usr/local" "i686-unknown-linux-musl install directory"
|
||||
valopt musl-root-arm "/usr/local" "arm-unknown-linux-musleabi install directory"
|
||||
valopt musl-root-armhf "/usr/local" "arm-unknown-linux-musleabihf install directory"
|
||||
valopt musl-root-armv7 "/usr/local" "armv7-unknown-linux-musleabihf install directory"
|
||||
valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag"
|
||||
|
||||
if [ -e ${CFG_SRC_DIR}.git ]
|
||||
@ -717,8 +728,27 @@ case "$CFG_RELEASE_CHANNEL" in
|
||||
nightly )
|
||||
msg "overriding settings for $CFG_RELEASE_CHANNEL"
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
|
||||
# FIXME(#37364) shouldn't have to disable this on windows-gnu
|
||||
case "$CFG_BUILD" in
|
||||
*-pc-windows-gnu)
|
||||
;;
|
||||
*)
|
||||
CFG_ENABLE_DEBUGINFO_LINES=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
dev | beta | stable)
|
||||
beta | stable)
|
||||
msg "overriding settings for $CFG_RELEASE_CHANNEL"
|
||||
case "$CFG_BUILD" in
|
||||
*-pc-windows-gnu)
|
||||
;;
|
||||
*)
|
||||
CFG_ENABLE_DEBUGINFO_LINES=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
dev)
|
||||
;;
|
||||
*)
|
||||
err "release channel must be 'dev', 'nightly', 'beta' or 'stable'"
|
||||
@ -748,6 +778,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; f
|
||||
if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
|
||||
|
||||
step_msg "looking for build programs"
|
||||
@ -762,9 +793,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
|
||||
err "Found $python_version, but Python 2.7 is required"
|
||||
fi
|
||||
|
||||
# Checking for node, but not required
|
||||
probe CFG_NODEJS nodejs node
|
||||
|
||||
# If we have no git directory then we are probably a tarball distribution
|
||||
# and shouldn't attempt to load submodules
|
||||
if [ ! -e ${CFG_SRC_DIR}.git ]
|
||||
@ -840,13 +868,6 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$CFG_GDB" ]
|
||||
then
|
||||
# Store GDB's version
|
||||
CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
|
||||
putvar CFG_GDB_VERSION
|
||||
fi
|
||||
|
||||
if [ -n "$CFG_LLDB" ]
|
||||
then
|
||||
# Store LLDB's version
|
||||
@ -1216,14 +1237,6 @@ do
|
||||
fi
|
||||
;;
|
||||
|
||||
|
||||
x86_64-*-musl | arm-*-musleabi)
|
||||
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
|
||||
then
|
||||
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
|
||||
fi
|
||||
;;
|
||||
|
||||
*-msvc)
|
||||
# There are three builds of cmake on windows: MSVC, MinGW and Cygwin
|
||||
# The Cygwin build does not have generators for Visual Studio, so
|
||||
@ -1642,8 +1655,8 @@ do
|
||||
("ccache gcc")
|
||||
LLVM_CXX_32="ccache"
|
||||
LLVM_CC_32="ccache"
|
||||
LLVM_CXX_32_ARG1="clang++"
|
||||
LLVM_CC_32_ARG1="clang"
|
||||
LLVM_CXX_32_ARG1="g++"
|
||||
LLVM_CC_32_ARG1="gcc"
|
||||
|
||||
LLVM_CXX_64="ccache"
|
||||
LLVM_CC_64="ccache"
|
||||
@ -1768,7 +1781,7 @@ do
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
|
||||
fi
|
||||
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ'"
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'"
|
||||
CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
|
||||
CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"
|
||||
|
||||
|
1
mk/cfg/aarch64-unknown-fuchsia.mk
Normal file
1
mk/cfg/aarch64-unknown-fuchsia.mk
Normal file
@ -0,0 +1 @@
|
||||
# rustbuild-only target
|
24
mk/cfg/wasm32-unknown-emscripten.mk
Normal file
24
mk/cfg/wasm32-unknown-emscripten.mk
Normal file
@ -0,0 +1,24 @@
|
||||
# wasm32-unknown-emscripten configuration
|
||||
CC_wasm32-unknown-emscripten=emcc
|
||||
CXX_wasm32-unknown-emscripten=em++
|
||||
CPP_wasm32-unknown-emscripten=$(CPP)
|
||||
AR_wasm32-unknown-emscripten=emar
|
||||
CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
|
||||
CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1
|
||||
CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
|
||||
CFG_INSTALL_NAME_wasm32-unknown-emscripten =
|
||||
CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
|
||||
CFG_WINDOWSY_wasm32-unknown-emscripten :=
|
||||
CFG_UNIXY_wasm32-unknown-emscripten := 1
|
||||
CFG_LDPATH_wasm32-unknown-emscripten :=
|
||||
CFG_RUN_wasm32-unknown-emscripten=$(2)
|
||||
CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
|
||||
CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
|
||||
CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1
|
1
mk/cfg/x86_64-unknown-fuchsia.mk
Normal file
1
mk/cfg/x86_64-unknown-fuchsia.mk
Normal file
@ -0,0 +1 @@
|
||||
# rustbuild-only target
|
19
mk/crates.mk
19
mk/crates.mk
@ -59,9 +59,9 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures rustc_platform_intrinsics rustc_errors \
|
||||
rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
|
||||
rustc_const_eval rustc_const_math rustc_incremental rustc_macro
|
||||
HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
|
||||
flate arena graphviz log serialize
|
||||
rustc_const_eval rustc_const_math rustc_incremental proc_macro
|
||||
HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos $(RUSTC_CRATES) \
|
||||
rustdoc fmt_macros flate arena graphviz log serialize
|
||||
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
|
||||
|
||||
DEPS_core :=
|
||||
@ -101,9 +101,10 @@ DEPS_term := std
|
||||
DEPS_test := std getopts term native:rust_test_helpers
|
||||
|
||||
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos
|
||||
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro
|
||||
DEPS_proc_macro := syntax syntax_pos rustc_plugin log
|
||||
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro
|
||||
DEPS_syntax_pos := serialize
|
||||
DEPS_proc_macro_tokens := syntax syntax_pos log
|
||||
DEPS_proc_macro_plugin := syntax syntax_pos rustc_plugin log proc_macro_tokens
|
||||
|
||||
DEPS_rustc_const_math := std syntax log serialize
|
||||
DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \
|
||||
@ -118,15 +119,15 @@ DEPS_rustc_data_structures := std log serialize libc
|
||||
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
|
||||
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
|
||||
rustc_trans rustc_privacy rustc_lint rustc_plugin \
|
||||
rustc_metadata syntax_ext proc_macro \
|
||||
rustc_metadata syntax_ext proc_macro_plugin \
|
||||
rustc_passes rustc_save_analysis rustc_const_eval \
|
||||
rustc_incremental syntax_pos rustc_errors rustc_macro
|
||||
rustc_incremental syntax_pos rustc_errors proc_macro rustc_data_structures
|
||||
DEPS_rustc_errors := log libc serialize syntax_pos
|
||||
DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval
|
||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
||||
DEPS_rustc_macro := std syntax
|
||||
DEPS_proc_macro := std syntax
|
||||
DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \
|
||||
rustc_macro syntax_ext
|
||||
proc_macro syntax_ext
|
||||
DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors
|
||||
DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags
|
||||
DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors
|
||||
|
36
mk/llvm.mk
36
mk/llvm.mk
@ -36,22 +36,27 @@ endif
|
||||
# If CFG_LLVM_ROOT is defined then we don't build LLVM ourselves
|
||||
ifeq ($(CFG_LLVM_ROOT),)
|
||||
|
||||
LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
|
||||
LLVM_STAMP_$(1) = $(S)src/rustllvm/llvm-auto-clean-trigger
|
||||
LLVM_DONE_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-finished-building
|
||||
|
||||
$$(LLVM_CONFIG_$(1)): $$(LLVM_DONE_$(1))
|
||||
|
||||
ifneq ($$(CFG_NINJA),)
|
||||
BUILD_LLVM_$(1) := $$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1))
|
||||
else ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
BUILD_LLVM_$(1) := $$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
|
||||
--config $$(LLVM_BUILD_CONFIG_MODE)
|
||||
else
|
||||
BUILD_LLVM_$(1) := $$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
|
||||
endif
|
||||
|
||||
$$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1))
|
||||
@$$(call E, cmake: llvm)
|
||||
ifneq ($$(CFG_NINJA),)
|
||||
$$(Q)$$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1))
|
||||
else ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
$$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
|
||||
--config $$(LLVM_BUILD_CONFIG_MODE)
|
||||
else
|
||||
$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
|
||||
endif
|
||||
$$(Q)touch $$@
|
||||
$$(Q)if ! cmp $$(LLVM_STAMP_$(1)) $$(LLVM_DONE_$(1)); then \
|
||||
$$(MAKE) clean-llvm$(1); \
|
||||
$$(BUILD_LLVM_$(1)); \
|
||||
fi
|
||||
$$(Q)cp $$(LLVM_STAMP_$(1)) $$@
|
||||
|
||||
ifneq ($$(CFG_NINJA),)
|
||||
clean-llvm$(1):
|
||||
@ -75,17 +80,6 @@ endif
|
||||
|
||||
$$(LLVM_AR_$(1)): $$(LLVM_CONFIG_$(1))
|
||||
|
||||
# This is used to independently force an LLVM clean rebuild
|
||||
# when we changed something not otherwise captured by builtin
|
||||
# dependencies. In these cases, commit a change that touches
|
||||
# the stamp in the source dir.
|
||||
$$(LLVM_STAMP_$(1)): $$(S)src/rustllvm/llvm-auto-clean-trigger
|
||||
@$$(call E, make: cleaning llvm)
|
||||
$$(Q)touch $$@.start_time
|
||||
$$(Q)$$(MAKE) clean-llvm$(1)
|
||||
@$$(call E, make: done cleaning llvm)
|
||||
touch -r $$@.start_time $$@ && rm $$@.start_time
|
||||
|
||||
ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1)
|
||||
LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
|
||||
-print-file-name=lib$(CFG_STDCPP_NAME).a))"
|
||||
|
20
mk/main.mk
20
mk/main.mk
@ -13,12 +13,12 @@
|
||||
######################################################################
|
||||
|
||||
# The version number
|
||||
CFG_RELEASE_NUM=1.13.0
|
||||
CFG_RELEASE_NUM=1.14.0
|
||||
|
||||
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
||||
# NB Make sure it starts with a dot to conform to semver pre-release
|
||||
# versions (section 9)
|
||||
CFG_PRERELEASE_VERSION=.3
|
||||
CFG_PRERELEASE_VERSION=.5
|
||||
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
||||
# This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
|
||||
@ -53,11 +53,12 @@ endif
|
||||
# versions in the same place
|
||||
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
|
||||
|
||||
# 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
|
||||
ifdef CFG_ENABLE_LOCAL_RUST
|
||||
ifeq ($(CFG_RELEASE),\
|
||||
$(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT)))
|
||||
CFG_INFO := $(info cfg: auto-detected local-rebuild $(CFG_RELEASE))
|
||||
SEMVER_PREFIX=$(shell echo $(CFG_RELEASE_NUM) | grep -E -o '^[[:digit:]]+\.[[:digit:]]+')
|
||||
LOCAL_RELEASE=$(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT))
|
||||
ifneq (,$(filter $(SEMVER_PREFIX).%,$(LOCAL_RELEASE)))
|
||||
CFG_INFO := $(info cfg: auto-detected local-rebuild using $(LOCAL_RELEASE))
|
||||
CFG_ENABLE_LOCAL_REBUILD = 1
|
||||
endif
|
||||
endif
|
||||
@ -141,6 +142,9 @@ endif
|
||||
ifdef CFG_ENABLE_DEBUGINFO
|
||||
$(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO))
|
||||
CFG_RUSTC_FLAGS += -g
|
||||
else ifdef CFG_ENABLE_DEBUGINFO_LINES
|
||||
$(info cfg: enabling line number debuginfo (CFG_ENABLE_DEBUGINFO_LINES))
|
||||
CFG_RUSTC_FLAGS += -Cdebuginfo=1
|
||||
endif
|
||||
|
||||
ifdef SAVE_TEMPS
|
||||
@ -281,7 +285,7 @@ endif
|
||||
# LLVM macros
|
||||
######################################################################
|
||||
|
||||
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
|
||||
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
|
||||
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
|
||||
interpreter instrumentation
|
||||
|
||||
@ -376,7 +380,7 @@ endif
|
||||
|
||||
# FIXME: Transitionary measure to bootstrap using the old bootstrap logic.
|
||||
# Remove this once the bootstrap compiler uses the new login in Issue #36548.
|
||||
export RUSTC_BOOTSTRAP_KEY=5c6cf767
|
||||
export RUSTC_BOOTSTRAP_KEY=62b3e239
|
||||
|
||||
######################################################################
|
||||
# Per-stage targets and runner
|
||||
|
@ -632,6 +632,7 @@ endif
|
||||
# is a separate choice from whether to pass `-g` when building the
|
||||
# compiler and standard library themselves.
|
||||
CTEST_RUSTC_FLAGS := $$(subst -g,,$$(CTEST_RUSTC_FLAGS))
|
||||
CTEST_RUSTC_FLAGS := $$(subst -Cdebuginfo=1,,$$(CTEST_RUSTC_FLAGS))
|
||||
ifdef CFG_ENABLE_DEBUGINFO_TESTS
|
||||
CTEST_RUSTC_FLAGS += -g
|
||||
endif
|
||||
@ -647,7 +648,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \
|
||||
--host $(3) \
|
||||
--docck-python $$(CFG_PYTHON) \
|
||||
--lldb-python $$(CFG_LLDB_PYTHON) \
|
||||
--gdb-version="$(CFG_GDB_VERSION)" \
|
||||
--gdb="$(CFG_GDB)" \
|
||||
--lldb-version="$(CFG_LLDB_VERSION)" \
|
||||
--llvm-version="$$(LLVM_VERSION_$(3))" \
|
||||
--android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \
|
||||
|
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" }
|
||||
gcc = "0.3.36"
|
||||
libc = "0.2"
|
||||
md5 = "0.1"
|
||||
regex = "0.1.73"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = "0.2"
|
||||
kernel32-sys = "0.2"
|
||||
|
@ -10,8 +10,64 @@ system.
|
||||
|
||||
## Using rustbuild
|
||||
|
||||
When configuring Rust via `./configure`, pass the following to enable building
|
||||
via this build system:
|
||||
The rustbuild build system has a primary entry point, a top level `x.py` script:
|
||||
|
||||
```
|
||||
python ./x.py build
|
||||
```
|
||||
|
||||
Note that if you're on Unix you should be able to execute the script directly:
|
||||
|
||||
```
|
||||
./x.py build
|
||||
```
|
||||
|
||||
The script accepts commands, flags, and filters to determine what to do:
|
||||
|
||||
* `build` - a general purpose command for compiling code. Alone `build` will
|
||||
bootstrap the entire compiler, and otherwise arguments passed indicate what to
|
||||
build. For example:
|
||||
|
||||
```
|
||||
# build the whole compiler
|
||||
./x.py build
|
||||
|
||||
# build the stage1 compier
|
||||
./x.py build --stage 1
|
||||
|
||||
# build stage0 libstd
|
||||
./x.py build --stage 0 src/libstd
|
||||
|
||||
# build a particular crate in stage0
|
||||
./x.py build --stage 0 src/libtest
|
||||
```
|
||||
|
||||
* `test` - a command for executing unit tests. Like the `build` command this
|
||||
will execute the entire test suite by default, and otherwise it can be used to
|
||||
select which test suite is run:
|
||||
|
||||
```
|
||||
# run all unit tests
|
||||
./x.py test
|
||||
|
||||
# execute the run-pass test suite
|
||||
./x.py test src/test/run-pass
|
||||
|
||||
# execute only some tests in the run-pass test suite
|
||||
./x.py test src/test/run-pass --filter my-filter
|
||||
|
||||
# execute tests in the standard library in stage0
|
||||
./x.py test --stage 0 src/libstd
|
||||
|
||||
# execute all doc tests
|
||||
./x.py test src/doc
|
||||
```
|
||||
|
||||
* `doc` - a command for building documentation. Like above can take arguments
|
||||
for what to document.
|
||||
|
||||
If you're more used to `./configure` and `make`, however, then you can also
|
||||
configure the build system to use rustbuild instead of the old makefiles:
|
||||
|
||||
```
|
||||
./configure --enable-rustbuild
|
||||
@ -19,15 +75,7 @@ make
|
||||
```
|
||||
|
||||
Afterwards the `Makefile` which is generated will have a few commands like
|
||||
`make check`, `make tidy`, etc. For finer-grained control, the
|
||||
`bootstrap.py` entry point can be used:
|
||||
|
||||
```
|
||||
python src/bootstrap/bootstrap.py
|
||||
```
|
||||
|
||||
This accepts a number of options like `--stage` and `--step` which can configure
|
||||
what's actually being done.
|
||||
`make check`, `make tidy`, etc.
|
||||
|
||||
## Configuring rustbuild
|
||||
|
||||
@ -47,7 +95,7 @@ being invoked manually (via the python script).
|
||||
The rustbuild build system goes through a few phases to actually build the
|
||||
compiler. What actually happens when you invoke rustbuild is:
|
||||
|
||||
1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is
|
||||
1. The entry point script, `x.py` is run. This script is
|
||||
responsible for downloading the stage0 compiler/Cargo binaries, and it then
|
||||
compiles the build system itself (this folder). Finally, it then invokes the
|
||||
actual `bootstrap` binary build system.
|
||||
|
@ -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
|
||||
@ -64,9 +65,10 @@ fn main() {
|
||||
|
||||
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
|
||||
@ -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));
|
||||
|
@ -29,10 +29,12 @@ fn main() {
|
||||
|
||||
let mut cmd = Command::new(rustdoc);
|
||||
cmd.args(&args)
|
||||
.arg("--cfg").arg(format!("stage{}", stage))
|
||||
.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),
|
||||
|
@ -344,6 +344,22 @@ class RustBuild(object):
|
||||
ostype += 'eabihf'
|
||||
elif cputype == 'aarch64':
|
||||
cputype = 'aarch64'
|
||||
elif cputype == 'mips':
|
||||
if sys.byteorder == 'big':
|
||||
cputype = 'mips'
|
||||
elif sys.byteorder == 'little':
|
||||
cputype = 'mipsel'
|
||||
else:
|
||||
raise ValueError('unknown byteorder: ' + sys.byteorder)
|
||||
elif cputype == 'mips64':
|
||||
if sys.byteorder == 'big':
|
||||
cputype = 'mips64'
|
||||
elif sys.byteorder == 'little':
|
||||
cputype = 'mips64el'
|
||||
else:
|
||||
raise ValueError('unknown byteorder: ' + sys.byteorder)
|
||||
# only the n64 ABI is supported, indicate it
|
||||
ostype += 'abi64'
|
||||
elif cputype in {'powerpc', 'ppc', 'ppc64'}:
|
||||
cputype = 'powerpc'
|
||||
elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
|
||||
@ -399,12 +415,10 @@ def main():
|
||||
|
||||
# Run the bootstrap
|
||||
args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
|
||||
args.append('--src')
|
||||
args.append(rb.rust_root)
|
||||
args.append('--build')
|
||||
args.append(rb.build)
|
||||
args.extend(sys.argv[1:])
|
||||
env = os.environ.copy()
|
||||
env["BUILD"] = rb.build
|
||||
env["SRC"] = rb.rust_root
|
||||
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
|
||||
rb.run(args, env)
|
||||
|
||||
|
@ -13,9 +13,9 @@
|
||||
//! This file implements the various regression test suites that we execute on
|
||||
//! our CI.
|
||||
|
||||
use std::collections::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;
|
||||
|
||||
@ -108,6 +108,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());
|
||||
@ -139,8 +143,8 @@ pub fn compiletest(build: &Build,
|
||||
cmd.arg("--lldb-python").arg(python_default);
|
||||
}
|
||||
|
||||
if let Some(ref vers) = build.gdb_version {
|
||||
cmd.arg("--gdb-version").arg(vers);
|
||||
if let Some(ref gdb) = build.config.gdb {
|
||||
cmd.arg("--gdb").arg(gdb);
|
||||
}
|
||||
if let Some(ref vers) = build.lldb_version {
|
||||
cmd.arg("--lldb-version").arg(vers);
|
||||
@ -152,12 +156,16 @@ pub fn compiletest(build: &Build,
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
|
||||
cmd.args(&build.flags.args);
|
||||
cmd.args(&build.flags.cmd.test_args());
|
||||
|
||||
if build.config.verbose || build.flags.verbose {
|
||||
cmd.arg("--verbose");
|
||||
}
|
||||
|
||||
if build.config.quiet_tests {
|
||||
cmd.arg("--quiet");
|
||||
}
|
||||
|
||||
// Only pass correct values for these flags for the `run-make` suite as it
|
||||
// requires that a C++ compiler was configured which isn't always the case.
|
||||
if suite == "run-make" {
|
||||
@ -248,7 +256,13 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
|
||||
build.add_rustc_lib_path(compiler, &mut cmd);
|
||||
cmd.arg("--test");
|
||||
cmd.arg(markdown);
|
||||
cmd.arg("--test-args").arg(build.flags.args.join(" "));
|
||||
|
||||
let mut test_args = build.flags.cmd.test_args().join(" ");
|
||||
if build.config.quiet_tests {
|
||||
test_args.push_str(" --quiet");
|
||||
}
|
||||
cmd.arg("--test-args").arg(test_args);
|
||||
|
||||
build.run(&mut cmd);
|
||||
}
|
||||
|
||||
@ -259,56 +273,58 @@ 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()),
|
||||
mode: Mode,
|
||||
krate: Option<&str>) {
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
continue
|
||||
match krate {
|
||||
Some(krate) => {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
lines.next(); // skip `version = ...`
|
||||
|
||||
// skip crates.io or otherwise non-path crates
|
||||
if let Some(line) = lines.next() {
|
||||
if line.starts_with("source") {
|
||||
continue
|
||||
None => {
|
||||
let mut visited = HashSet::new();
|
||||
let mut next = vec![root];
|
||||
while let Some(name) = next.pop() {
|
||||
// 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 !name.contains("jemalloc") {
|
||||
cargo.arg("-p").arg(name);
|
||||
}
|
||||
for dep in build.crates[name].deps.iter() {
|
||||
if visited.insert(dep) {
|
||||
next.push(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
cargo.arg("-p").arg(crate_name);
|
||||
}
|
||||
|
||||
// The tests are going to run with the *target* libraries, so we need to
|
||||
@ -320,11 +336,19 @@ pub fn krate(build: &Build,
|
||||
dylib_path.insert(0, build.sysroot_libdir(compiler, target));
|
||||
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
if build.config.quiet_tests {
|
||||
cargo.arg("--");
|
||||
cargo.arg("--quiet");
|
||||
}
|
||||
|
||||
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);
|
||||
cargo.args(&build.flags.cmd.test_args());
|
||||
build.run(&mut cargo);
|
||||
}
|
||||
}
|
||||
@ -356,7 +380,7 @@ fn krate_android(build: &Build,
|
||||
target = target,
|
||||
test = test_file_name,
|
||||
log = log,
|
||||
args = build.flags.args.join(" "));
|
||||
args = build.flags.cmd.test_args().join(" "));
|
||||
|
||||
let output = output(Command::new("adb").arg("shell").arg(&program));
|
||||
println!("{}", output);
|
||||
@ -371,6 +395,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 +434,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());
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
//! directory as we want that cached between builds.
|
||||
|
||||
use std::fs;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::path::Path;
|
||||
|
||||
use Build;
|
||||
@ -25,24 +26,58 @@ pub fn clean(build: &Build) {
|
||||
rm_rf(build, &build.out.join("tmp"));
|
||||
|
||||
for host in build.config.host.iter() {
|
||||
let entries = match build.out.join(host).read_dir() {
|
||||
Ok(iter) => iter,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let out = build.out.join(host);
|
||||
|
||||
rm_rf(build, &out.join("doc"));
|
||||
|
||||
for stage in 0..4 {
|
||||
rm_rf(build, &out.join(format!("stage{}", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-std", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-tools", stage)));
|
||||
rm_rf(build, &out.join(format!("stage{}-test", stage)));
|
||||
for entry in entries {
|
||||
let entry = t!(entry);
|
||||
if entry.file_name().to_str() == Some("llvm") {
|
||||
continue
|
||||
}
|
||||
let path = t!(entry.path().canonicalize());
|
||||
rm_rf(build, &path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rm_rf(build: &Build, path: &Path) {
|
||||
if path.exists() {
|
||||
build.verbose(&format!("removing `{}`", path.display()));
|
||||
t!(fs::remove_dir_all(path));
|
||||
if !path.exists() {
|
||||
return
|
||||
}
|
||||
|
||||
for file in t!(fs::read_dir(path)) {
|
||||
let file = t!(file).path();
|
||||
|
||||
if file.is_dir() {
|
||||
rm_rf(build, &file);
|
||||
} else {
|
||||
// On windows we can't remove a readonly file, and git will
|
||||
// often clone files as readonly. As a result, we have some
|
||||
// special logic to remove readonly files on windows.
|
||||
do_op(&file, "remove file", |p| fs::remove_file(p));
|
||||
}
|
||||
}
|
||||
do_op(path, "remove dir", |p| fs::remove_dir(p));
|
||||
}
|
||||
|
||||
fn do_op<F>(path: &Path, desc: &str, mut f: F)
|
||||
where F: FnMut(&Path) -> io::Result<()>
|
||||
{
|
||||
match f(path) {
|
||||
Ok(()) => {}
|
||||
Err(ref e) if cfg!(windows) &&
|
||||
e.kind() == ErrorKind::PermissionDenied => {
|
||||
let mut p = t!(path.metadata()).permissions();
|
||||
p.set_readonly(false);
|
||||
t!(fs::set_permissions(path, p));
|
||||
f(path).unwrap_or_else(|e| {
|
||||
panic!("failed to {} {}: {}", desc, path.display(), e);
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("failed to {} {}: {}", desc, path.display(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -78,8 +64,8 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libstd_stamp(build, compiler, target));
|
||||
std_link(build, target, compiler, compiler.host);
|
||||
update_mtime(&libstd_stamp(build, &compiler, target));
|
||||
std_link(build, target, compiler.stage, compiler.host);
|
||||
}
|
||||
|
||||
/// Link all libstd rlibs/dylibs into the sysroot location.
|
||||
@ -88,11 +74,12 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
/// by `compiler` into `host`'s sysroot.
|
||||
pub fn std_link(build: &Build,
|
||||
target: &str,
|
||||
compiler: &Compiler,
|
||||
stage: u32,
|
||||
host: &str) {
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let target_compiler = Compiler::new(compiler.stage, host);
|
||||
let libdir = build.sysroot_libdir(&target_compiler, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
|
||||
let out_dir = build.cargo_out(&compiler, Mode::Libstd, target);
|
||||
|
||||
// If we're linking one compiler host's output into another, then we weren't
|
||||
// called from the `std` method above. In that case we clean out what's
|
||||
@ -104,16 +91,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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,7 +147,7 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libtest_stamp(build, compiler, target));
|
||||
test_link(build, target, compiler, compiler.host);
|
||||
test_link(build, target, compiler.stage, compiler.host);
|
||||
}
|
||||
|
||||
/// Link all libtest rlibs/dylibs into the sysroot location.
|
||||
@ -169,11 +156,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
/// by `compiler` into `host`'s sysroot.
|
||||
pub fn test_link(build: &Build,
|
||||
target: &str,
|
||||
compiler: &Compiler,
|
||||
stage: u32,
|
||||
host: &str) {
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let target_compiler = Compiler::new(compiler.stage, host);
|
||||
let libdir = build.sysroot_libdir(&target_compiler, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
|
||||
let out_dir = build.cargo_out(&compiler, Mode::Libtest, target);
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
}
|
||||
|
||||
@ -232,7 +220,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
}
|
||||
build.run(&mut cargo);
|
||||
|
||||
rustc_link(build, target, compiler, compiler.host);
|
||||
rustc_link(build, target, compiler.stage, compiler.host);
|
||||
}
|
||||
|
||||
/// Link all librustc rlibs/dylibs into the sysroot location.
|
||||
@ -241,11 +229,12 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
/// by `compiler` into `host`'s sysroot.
|
||||
pub fn rustc_link(build: &Build,
|
||||
target: &str,
|
||||
compiler: &Compiler,
|
||||
stage: u32,
|
||||
host: &str) {
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let target_compiler = Compiler::new(compiler.stage, host);
|
||||
let libdir = build.sysroot_libdir(&target_compiler, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
|
||||
let out_dir = build.cargo_out(&compiler, Mode::Librustc, target);
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
}
|
||||
|
||||
@ -273,7 +262,10 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
|
||||
/// must have been previously produced by the `stage - 1` build.config.build
|
||||
/// compiler.
|
||||
pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
|
||||
assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded");
|
||||
// nothing to do in stage0
|
||||
if stage == 0 {
|
||||
return
|
||||
}
|
||||
// The compiler that we're assembling
|
||||
let target_compiler = Compiler::new(stage, host);
|
||||
|
||||
|
@ -23,6 +23,7 @@ use std::process;
|
||||
use num_cpus;
|
||||
use rustc_serialize::Decodable;
|
||||
use toml::{Parser, Decoder, Value};
|
||||
use util::push_exe_path;
|
||||
|
||||
/// Global configuration for the entire build and/or bootstrap.
|
||||
///
|
||||
@ -56,6 +57,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>,
|
||||
@ -76,11 +78,16 @@ pub struct Config {
|
||||
|
||||
// misc
|
||||
pub channel: String,
|
||||
pub quiet_tests: bool,
|
||||
// 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>,
|
||||
pub gdb: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
@ -117,6 +124,8 @@ struct Build {
|
||||
rustc: Option<String>,
|
||||
compiler_docs: Option<bool>,
|
||||
docs: Option<bool>,
|
||||
submodules: Option<bool>,
|
||||
gdb: Option<String>,
|
||||
}
|
||||
|
||||
/// TOML representation of how the LLVM build is configured.
|
||||
@ -137,6 +146,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 +168,7 @@ struct TomlTarget {
|
||||
cc: Option<String>,
|
||||
cxx: Option<String>,
|
||||
android_ndk: Option<String>,
|
||||
musl_root: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -219,8 +230,10 @@ impl Config {
|
||||
}
|
||||
config.rustc = build.rustc.map(PathBuf::from);
|
||||
config.cargo = build.cargo.map(PathBuf::from);
|
||||
config.gdb = build.gdb.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 +246,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 +282,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,11 +337,13 @@ 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),
|
||||
("OPTIMIZE_TESTS", self.rust_optimize_tests),
|
||||
("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
|
||||
("QUIET_TESTS", self.quiet_tests),
|
||||
("LOCAL_REBUILD", self.local_rebuild),
|
||||
("NINJA", self.ninja),
|
||||
("CODEGEN_TESTS", self.codegen_tests),
|
||||
@ -343,7 +360,37 @@ impl Config {
|
||||
.collect();
|
||||
}
|
||||
"CFG_MUSL_ROOT" if value.len() > 0 => {
|
||||
self.musl_root = Some(PathBuf::from(value));
|
||||
self.musl_root = Some(parse_configure_path(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(parse_configure_path(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(parse_configure_path(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(parse_configure_path(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(parse_configure_path(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(parse_configure_path(value));
|
||||
}
|
||||
"CFG_DEFAULT_AR" if value.len() > 0 => {
|
||||
self.rustc_default_ar = Some(value.to_string());
|
||||
@ -351,53 +398,63 @@ impl Config {
|
||||
"CFG_DEFAULT_LINKER" if value.len() > 0 => {
|
||||
self.rustc_default_linker = Some(value.to_string());
|
||||
}
|
||||
"CFG_GDB" if value.len() > 0 => {
|
||||
self.gdb = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_RELEASE_CHANNEL" => {
|
||||
self.channel = value.to_string();
|
||||
}
|
||||
"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());
|
||||
let root = PathBuf::from(value);
|
||||
target.llvm_config = Some(root.join("bin/llvm-config"));
|
||||
let root = parse_configure_path(value);
|
||||
target.llvm_config = Some(push_exe_path(root, &["bin", "llvm-config"]));
|
||||
}
|
||||
"CFG_JEMALLOC_ROOT" if value.len() > 0 => {
|
||||
let target = self.target_config.entry(self.build.clone())
|
||||
.or_insert(Target::default());
|
||||
target.jemalloc = Some(PathBuf::from(value));
|
||||
target.jemalloc = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
|
||||
let target = "arm-linux-androideabi".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.ndk = Some(PathBuf::from(value));
|
||||
target.ndk = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_ARMV7_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
|
||||
let target = "armv7-linux-androideabi".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.ndk = Some(PathBuf::from(value));
|
||||
target.ndk = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => {
|
||||
let target = "i686-linux-android".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.ndk = Some(PathBuf::from(value));
|
||||
target.ndk = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => {
|
||||
let target = "aarch64-linux-android".to_string();
|
||||
let target = self.target_config.entry(target)
|
||||
.or_insert(Target::default());
|
||||
target.ndk = Some(PathBuf::from(value));
|
||||
target.ndk = Some(parse_configure_path(value));
|
||||
}
|
||||
"CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
|
||||
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));
|
||||
let path = parse_configure_path(value);
|
||||
self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
|
||||
self.cargo = Some(push_exe_path(path, &["bin", "cargo"]));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -405,6 +462,30 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn parse_configure_path(path: &str) -> PathBuf {
|
||||
path.into()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn parse_configure_path(path: &str) -> PathBuf {
|
||||
// on windows, configure produces unix style paths e.g. /c/some/path but we
|
||||
// only want real windows paths
|
||||
|
||||
use std::process::Command;
|
||||
use build_helper;
|
||||
|
||||
// '/' is invalid in windows paths, so we can detect unix paths by the presence of it
|
||||
if !path.contains('/') {
|
||||
return path.into();
|
||||
}
|
||||
|
||||
let win_path = build_helper::output(Command::new("cygpath").arg("-w").arg(path));
|
||||
let win_path = win_path.trim();
|
||||
|
||||
win_path.into()
|
||||
}
|
||||
|
||||
fn set<T>(field: &mut T, val: Option<T>) {
|
||||
if let Some(v) = val {
|
||||
*field = v;
|
||||
|
@ -76,6 +76,12 @@
|
||||
# library and facade crates.
|
||||
#compiler-docs = false
|
||||
|
||||
# Indicate whether submodules are managed and updated automatically.
|
||||
#submodules = true
|
||||
|
||||
# The path to (or name of) the GDB executable to use
|
||||
#gdb = "gdb"
|
||||
|
||||
# =============================================================================
|
||||
# Options for compiling Rust code itself
|
||||
# =============================================================================
|
||||
@ -96,6 +102,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);
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use {Build, Compiler, Mode};
|
||||
@ -30,8 +29,9 @@ use util::{up_to_date, cp_r};
|
||||
///
|
||||
/// This will not actually generate any documentation if the documentation has
|
||||
/// already been generated.
|
||||
pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) {
|
||||
t!(fs::create_dir_all(out));
|
||||
pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str) {
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
let out = out.join(name);
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
@ -57,9 +57,10 @@ pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path)
|
||||
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
|
||||
///
|
||||
/// In the end, this is just a glorified wrapper around rustdoc!
|
||||
pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn standalone(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} standalone ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
|
||||
@ -109,7 +110,7 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
.arg("--html-in-header").arg(&favicon)
|
||||
.arg("--markdown-playground-url")
|
||||
.arg("https://play.rust-lang.org/")
|
||||
.arg("-o").arg(out)
|
||||
.arg("-o").arg(&out)
|
||||
.arg(&path);
|
||||
|
||||
if filename == "reference.md" {
|
||||
@ -131,9 +132,10 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
///
|
||||
/// This will generate all documentation for the standard library and its
|
||||
/// dependencies. This is largely just a wrapper around `cargo doc`.
|
||||
pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn std(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} std ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let out_dir = build.stage_out(&compiler, Mode::Libstd)
|
||||
.join(target).join("doc");
|
||||
@ -146,16 +148,17 @@ pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
|
||||
.arg("--features").arg(build.std_features());
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, out)
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
||||
/// Compile all libtest documentation.
|
||||
///
|
||||
/// This will generate all documentation for libtest and its dependencies. This
|
||||
/// is largely just a wrapper around `cargo doc`.
|
||||
pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn test(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} test ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let out_dir = build.stage_out(&compiler, Mode::Libtest)
|
||||
.join(target).join("doc");
|
||||
@ -167,16 +170,17 @@ pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, out)
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
||||
/// Generate all compiler documentation.
|
||||
///
|
||||
/// This will generate all documentation for the compiler libraries and their
|
||||
/// dependencies. This is largely just a wrapper around `cargo doc`.
|
||||
pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn rustc(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} compiler ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let out_dir = build.stage_out(&compiler, Mode::Librustc)
|
||||
.join(target).join("doc");
|
||||
@ -189,14 +193,15 @@ pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
.arg(build.src.join("src/rustc/Cargo.toml"))
|
||||
.arg("--features").arg(build.rustc_features());
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, out)
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
||||
/// Generates the HTML rendered error-index by running the
|
||||
/// `error_index_generator` tool.
|
||||
pub fn error_index(build: &Build, stage: u32, target: &str, out: &Path) {
|
||||
pub fn error_index(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} error index ({})", stage, target);
|
||||
t!(fs::create_dir_all(out));
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let mut index = build.tool_cmd(&compiler, "error_index_generator");
|
||||
index.arg("html");
|
||||
|
@ -13,30 +13,46 @@
|
||||
//! This module implements the command-line parsing of the build system which
|
||||
//! has various flags to configure how it's run.
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::slice;
|
||||
|
||||
use getopts::Options;
|
||||
use getopts::{Matches, Options};
|
||||
|
||||
use Build;
|
||||
use config::Config;
|
||||
use metadata;
|
||||
use step;
|
||||
|
||||
/// Deserialized version of all flags for this compile.
|
||||
pub struct Flags {
|
||||
pub verbose: bool,
|
||||
pub stage: Option<u32>,
|
||||
pub build: String,
|
||||
pub host: Filter,
|
||||
pub target: Filter,
|
||||
pub step: Vec<String>,
|
||||
pub host: Vec<String>,
|
||||
pub target: Vec<String>,
|
||||
pub config: Option<PathBuf>,
|
||||
pub src: Option<PathBuf>,
|
||||
pub jobs: Option<u32>,
|
||||
pub args: Vec<String>,
|
||||
pub clean: bool,
|
||||
pub cmd: Subcommand,
|
||||
}
|
||||
|
||||
pub struct Filter {
|
||||
values: Vec<String>,
|
||||
pub enum Subcommand {
|
||||
Build {
|
||||
paths: Vec<PathBuf>,
|
||||
},
|
||||
Doc {
|
||||
paths: Vec<PathBuf>,
|
||||
},
|
||||
Test {
|
||||
paths: Vec<PathBuf>,
|
||||
test_args: Vec<String>,
|
||||
},
|
||||
Clean,
|
||||
Dist {
|
||||
install: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
@ -44,29 +60,177 @@ impl Flags {
|
||||
let mut opts = Options::new();
|
||||
opts.optflag("v", "verbose", "use verbose output");
|
||||
opts.optopt("", "config", "TOML configuration file for build", "FILE");
|
||||
opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
|
||||
opts.optmulti("", "host", "host targets to build", "HOST");
|
||||
opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD");
|
||||
opts.optmulti("", "target", "targets to build", "TARGET");
|
||||
opts.optmulti("s", "step", "build step to execute", "STEP");
|
||||
opts.optmulti("", "target", "target targets to build", "TARGET");
|
||||
opts.optopt("", "stage", "stage to build", "N");
|
||||
opts.optopt("", "src", "path to repo root", "DIR");
|
||||
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
|
||||
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
|
||||
opts.optflag("", "clean", "clean output directory");
|
||||
opts.optflag("h", "help", "print this help message");
|
||||
|
||||
let usage = |n| -> ! {
|
||||
let brief = format!("Usage: rust.py [options]");
|
||||
print!("{}", opts.usage(&brief));
|
||||
let usage = |n, opts: &Options| -> ! {
|
||||
let command = args.get(0).map(|s| &**s);
|
||||
let brief = format!("Usage: x.py {} [options] [<args>...]",
|
||||
command.unwrap_or("<command>"));
|
||||
|
||||
println!("{}", opts.usage(&brief));
|
||||
match command {
|
||||
Some("build") => {
|
||||
println!("\
|
||||
Arguments:
|
||||
This subcommand accepts a number of positional arguments of directories to
|
||||
the crates and/or artifacts to compile. For example:
|
||||
|
||||
./x.py build src/libcore
|
||||
./x.py build src/libproc_macro
|
||||
./x.py build src/libstd --stage 1
|
||||
|
||||
If no arguments are passed then the complete artifacts for that stage are
|
||||
also compiled.
|
||||
|
||||
./x.py build
|
||||
./x.py build --stage 1
|
||||
|
||||
For a quick build with a usable compile, you can pass:
|
||||
|
||||
./x.py build --stage 1 src/libtest
|
||||
");
|
||||
}
|
||||
|
||||
Some("test") => {
|
||||
println!("\
|
||||
Arguments:
|
||||
This subcommand accepts a number of positional arguments of directories to
|
||||
tests that should be compiled and run. For example:
|
||||
|
||||
./x.py test src/test/run-pass
|
||||
./x.py test src/test/run-pass/assert-*
|
||||
./x.py test src/libstd --test-args hash_map
|
||||
./x.py test src/libstd --stage 0
|
||||
|
||||
If no arguments are passed then the complete artifacts for that stage are
|
||||
compiled and tested.
|
||||
|
||||
./x.py test
|
||||
./x.py test --stage 1
|
||||
");
|
||||
}
|
||||
|
||||
Some("doc") => {
|
||||
println!("\
|
||||
Arguments:
|
||||
This subcommand accepts a number of positional arguments of directories of
|
||||
documentation to build. For example:
|
||||
|
||||
./x.py doc src/doc/book
|
||||
./x.py doc src/doc/nomicon
|
||||
./x.py doc src/libstd
|
||||
|
||||
If no arguments are passed then everything is documented:
|
||||
|
||||
./x.py doc
|
||||
./x.py doc --stage 1
|
||||
");
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(command) = command {
|
||||
if command == "build" ||
|
||||
command == "dist" ||
|
||||
command == "doc" ||
|
||||
command == "test" ||
|
||||
command == "clean" {
|
||||
println!("Available invocations:");
|
||||
if args.iter().any(|a| a == "-v") {
|
||||
let flags = Flags::parse(&["build".to_string()]);
|
||||
let mut config = Config::default();
|
||||
config.build = flags.build.clone();
|
||||
let mut build = Build::new(flags, config);
|
||||
metadata::build(&mut build);
|
||||
step::build_rules(&build).print_help(command);
|
||||
} else {
|
||||
println!(" ... elided, run `./x.py {} -h -v` to see",
|
||||
command);
|
||||
}
|
||||
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
|
||||
println!("\
|
||||
Subcommands:
|
||||
build Compile either the compiler or libraries
|
||||
test Build and run some test suites
|
||||
doc Build documentation
|
||||
clean Clean out build directories
|
||||
dist Build and/or install distribution artifacts
|
||||
|
||||
To learn more about a subcommand, run `./x.py <command> -h`
|
||||
");
|
||||
|
||||
process::exit(n);
|
||||
};
|
||||
|
||||
let m = opts.parse(args).unwrap_or_else(|e| {
|
||||
println!("failed to parse options: {}", e);
|
||||
usage(1);
|
||||
});
|
||||
if m.opt_present("h") {
|
||||
usage(0);
|
||||
if args.len() == 0 {
|
||||
println!("a command must be passed");
|
||||
usage(1, &opts);
|
||||
}
|
||||
let parse = |opts: &Options| {
|
||||
let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
|
||||
println!("failed to parse options: {}", e);
|
||||
usage(1, opts);
|
||||
});
|
||||
if m.opt_present("h") {
|
||||
usage(0, opts);
|
||||
}
|
||||
return m
|
||||
};
|
||||
|
||||
let cwd = t!(env::current_dir());
|
||||
let remaining_as_path = |m: &Matches| {
|
||||
m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let m: Matches;
|
||||
let cmd = match &args[0][..] {
|
||||
"build" => {
|
||||
m = parse(&opts);
|
||||
Subcommand::Build { paths: remaining_as_path(&m) }
|
||||
}
|
||||
"doc" => {
|
||||
m = parse(&opts);
|
||||
Subcommand::Doc { paths: remaining_as_path(&m) }
|
||||
}
|
||||
"test" => {
|
||||
opts.optmulti("", "test-args", "extra arguments", "ARGS");
|
||||
m = parse(&opts);
|
||||
Subcommand::Test {
|
||||
paths: remaining_as_path(&m),
|
||||
test_args: m.opt_strs("test-args"),
|
||||
}
|
||||
}
|
||||
"clean" => {
|
||||
m = parse(&opts);
|
||||
if m.free.len() > 0 {
|
||||
println!("clean takes no arguments");
|
||||
usage(1, &opts);
|
||||
}
|
||||
Subcommand::Clean
|
||||
}
|
||||
"dist" => {
|
||||
opts.optflag("", "install", "run installer as well");
|
||||
m = parse(&opts);
|
||||
Subcommand::Dist {
|
||||
install: m.opt_present("install"),
|
||||
}
|
||||
}
|
||||
cmd => {
|
||||
println!("unknown command: {}", cmd);
|
||||
usage(1, &opts);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
|
||||
if fs::metadata("config.toml").is_ok() {
|
||||
@ -78,26 +242,27 @@ impl Flags {
|
||||
|
||||
Flags {
|
||||
verbose: m.opt_present("v"),
|
||||
clean: m.opt_present("clean"),
|
||||
stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
|
||||
build: m.opt_str("build").unwrap(),
|
||||
host: Filter { values: m.opt_strs("host") },
|
||||
target: Filter { values: m.opt_strs("target") },
|
||||
step: m.opt_strs("step"),
|
||||
build: m.opt_str("build").unwrap_or_else(|| {
|
||||
env::var("BUILD").unwrap()
|
||||
}),
|
||||
host: m.opt_strs("host"),
|
||||
target: m.opt_strs("target"),
|
||||
config: cfg_file,
|
||||
src: m.opt_str("src").map(PathBuf::from),
|
||||
jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
|
||||
args: m.free.clone(),
|
||||
cmd: cmd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn contains(&self, name: &str) -> bool {
|
||||
self.values.len() == 0 || self.values.iter().any(|s| s == name)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> slice::Iter<String> {
|
||||
self.values.iter()
|
||||
impl Subcommand {
|
||||
pub fn test_args(&self) -> Vec<&str> {
|
||||
match *self {
|
||||
Subcommand::Test { ref test_args, .. } => {
|
||||
test_args.iter().flat_map(|s| s.split_whitespace()).collect()
|
||||
}
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
@ -58,10 +57,12 @@ mod channel;
|
||||
mod check;
|
||||
mod clean;
|
||||
mod compile;
|
||||
mod metadata;
|
||||
mod config;
|
||||
mod dist;
|
||||
mod doc;
|
||||
mod flags;
|
||||
mod install;
|
||||
mod native;
|
||||
mod sanity;
|
||||
mod step;
|
||||
@ -76,7 +77,7 @@ mod job {
|
||||
}
|
||||
|
||||
pub use config::Config;
|
||||
pub use flags::Flags;
|
||||
pub use flags::{Flags, Subcommand};
|
||||
|
||||
/// A structure representing a Rust compiler.
|
||||
///
|
||||
@ -123,13 +124,23 @@ pub struct Build {
|
||||
bootstrap_key_stage0: String,
|
||||
|
||||
// Probed tools at runtime
|
||||
gdb_version: Option<String>,
|
||||
lldb_version: Option<String>,
|
||||
lldb_python_dir: Option<String>,
|
||||
|
||||
// Runtime state filled in later on
|
||||
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
|
||||
cxx: HashMap<String, gcc::Tool>,
|
||||
crates: HashMap<String, Crate>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Crate {
|
||||
name: String,
|
||||
deps: Vec<String>,
|
||||
path: PathBuf,
|
||||
doc_step: String,
|
||||
build_step: String,
|
||||
test_step: String,
|
||||
}
|
||||
|
||||
/// The various "modes" of invoking Cargo.
|
||||
@ -162,7 +173,9 @@ impl Build {
|
||||
/// By default all build output will be placed in the current directory.
|
||||
pub fn new(flags: Flags, config: Config) -> Build {
|
||||
let cwd = t!(env::current_dir());
|
||||
let src = flags.src.clone().unwrap_or(cwd.clone());
|
||||
let src = flags.src.clone().or_else(|| {
|
||||
env::var_os("SRC").map(|x| x.into())
|
||||
}).unwrap_or(cwd.clone());
|
||||
let out = cwd.join("build");
|
||||
|
||||
let stage0_root = out.join(&config.build).join("stage0/bin");
|
||||
@ -196,7 +209,7 @@ impl Build {
|
||||
package_vers: String::new(),
|
||||
cc: HashMap::new(),
|
||||
cxx: HashMap::new(),
|
||||
gdb_version: None,
|
||||
crates: HashMap::new(),
|
||||
lldb_version: None,
|
||||
lldb_python_dir: None,
|
||||
}
|
||||
@ -204,13 +217,11 @@ impl Build {
|
||||
|
||||
/// Executes the entire build, as configured by the flags and configuration.
|
||||
pub fn build(&mut self) {
|
||||
use step::Source::*;
|
||||
|
||||
unsafe {
|
||||
job::setup();
|
||||
}
|
||||
|
||||
if self.flags.clean {
|
||||
if let Subcommand::Clean = self.flags.cmd {
|
||||
return clean::clean(self);
|
||||
}
|
||||
|
||||
@ -220,257 +231,22 @@ 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");
|
||||
self.update_submodules();
|
||||
self.verbose("learning about cargo");
|
||||
metadata::build(self);
|
||||
|
||||
// The main loop of the build system.
|
||||
//
|
||||
// The `step::all` function returns a topographically sorted list of all
|
||||
// steps that need to be executed as part of this build. Each step has a
|
||||
// corresponding entry in `step.rs` and indicates some unit of work that
|
||||
// needs to be done as part of the 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.
|
||||
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 } => {
|
||||
native::llvm(self, target.target);
|
||||
}
|
||||
TestHelpers { _dummy } => {
|
||||
native::test_helpers(self, target.target);
|
||||
}
|
||||
Libstd { compiler } => {
|
||||
compile::std(self, target.target, &compiler);
|
||||
}
|
||||
Libtest { compiler } => {
|
||||
compile::test(self, target.target, &compiler);
|
||||
}
|
||||
Librustc { compiler } => {
|
||||
compile::rustc(self, target.target, &compiler);
|
||||
}
|
||||
LibstdLink { compiler, host } => {
|
||||
compile::std_link(self, target.target, &compiler, host);
|
||||
}
|
||||
LibtestLink { compiler, host } => {
|
||||
compile::test_link(self, target.target, &compiler, host);
|
||||
}
|
||||
LibrustcLink { compiler, host } => {
|
||||
compile::rustc_link(self, target.target, &compiler, host);
|
||||
}
|
||||
Rustc { stage: 0 } => {
|
||||
// nothing to do...
|
||||
}
|
||||
Rustc { stage } => {
|
||||
compile::assemble_rustc(self, stage, target.target);
|
||||
}
|
||||
ToolLinkchecker { stage } => {
|
||||
compile::tool(self, stage, target.target, "linkchecker");
|
||||
}
|
||||
ToolRustbook { stage } => {
|
||||
compile::tool(self, stage, target.target, "rustbook");
|
||||
}
|
||||
ToolErrorIndex { stage } => {
|
||||
compile::tool(self, stage, target.target,
|
||||
"error_index_generator");
|
||||
}
|
||||
ToolCargoTest { stage } => {
|
||||
compile::tool(self, stage, target.target, "cargotest");
|
||||
}
|
||||
ToolTidy { stage } => {
|
||||
compile::tool(self, stage, target.target, "tidy");
|
||||
}
|
||||
ToolCompiletest { stage } => {
|
||||
compile::tool(self, stage, target.target, "compiletest");
|
||||
}
|
||||
DocBook { stage } => {
|
||||
doc::rustbook(self, stage, target.target, "book", &doc_out);
|
||||
}
|
||||
DocNomicon { stage } => {
|
||||
doc::rustbook(self, stage, target.target, "nomicon",
|
||||
&doc_out);
|
||||
}
|
||||
DocStandalone { stage } => {
|
||||
doc::standalone(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocStd { stage } => {
|
||||
doc::std(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocTest { stage } => {
|
||||
doc::test(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocRustc { stage } => {
|
||||
doc::rustc(self, stage, target.target, &doc_out);
|
||||
}
|
||||
DocErrorIndex { stage } => {
|
||||
doc::error_index(self, stage, target.target, &doc_out);
|
||||
}
|
||||
|
||||
CheckLinkcheck { stage } => {
|
||||
check::linkcheck(self, stage, target.target);
|
||||
}
|
||||
CheckCargoTest { stage } => {
|
||||
check::cargotest(self, stage, target.target);
|
||||
}
|
||||
CheckTidy { stage } => {
|
||||
check::tidy(self, stage, target.target);
|
||||
}
|
||||
CheckRPass { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-pass", "run-pass");
|
||||
}
|
||||
CheckRPassFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-pass", "run-pass-fulldeps");
|
||||
}
|
||||
CheckCFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"compile-fail", "compile-fail");
|
||||
}
|
||||
CheckCFailFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"compile-fail", "compile-fail-fulldeps")
|
||||
}
|
||||
CheckPFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"parse-fail", "parse-fail");
|
||||
}
|
||||
CheckRFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-fail", "run-fail");
|
||||
}
|
||||
CheckRFailFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-fail", "run-fail-fulldeps");
|
||||
}
|
||||
CheckPretty { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "pretty");
|
||||
}
|
||||
CheckPrettyRPass { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass");
|
||||
}
|
||||
CheckPrettyRPassFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass-fulldeps");
|
||||
}
|
||||
CheckPrettyRFail { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-fail");
|
||||
}
|
||||
CheckPrettyRFailFull { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-fail-fulldeps");
|
||||
}
|
||||
CheckPrettyRPassValgrind { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"pretty", "run-pass-valgrind");
|
||||
}
|
||||
CheckMirOpt { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"mir-opt", "mir-opt");
|
||||
}
|
||||
CheckCodegen { compiler } => {
|
||||
if self.config.codegen_tests {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen", "codegen");
|
||||
}
|
||||
}
|
||||
CheckCodegenUnits { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"codegen-units", "codegen-units");
|
||||
}
|
||||
CheckIncremental { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"incremental", "incremental");
|
||||
}
|
||||
CheckUi { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"ui", "ui");
|
||||
}
|
||||
CheckDebuginfo { compiler } => {
|
||||
if target.target.contains("msvc") {
|
||||
// nothing to do
|
||||
} else if target.target.contains("apple") {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"debuginfo-lldb", "debuginfo");
|
||||
} else {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"debuginfo-gdb", "debuginfo");
|
||||
}
|
||||
}
|
||||
CheckRustdoc { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"rustdoc", "rustdoc");
|
||||
}
|
||||
CheckRPassValgrind { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-pass-valgrind", "run-pass-valgrind");
|
||||
}
|
||||
CheckDocs { compiler } => {
|
||||
check::docs(self, &compiler);
|
||||
}
|
||||
CheckErrorIndex { compiler } => {
|
||||
check::error_index(self, &compiler);
|
||||
}
|
||||
CheckRMake { compiler } => {
|
||||
check::compiletest(self, &compiler, target.target,
|
||||
"run-make", "run-make")
|
||||
}
|
||||
CheckCrateStd { compiler } => {
|
||||
check::krate(self, &compiler, target.target, Mode::Libstd)
|
||||
}
|
||||
CheckCrateTest { compiler } => {
|
||||
check::krate(self, &compiler, target.target, Mode::Libtest)
|
||||
}
|
||||
CheckCrateRustc { compiler } => {
|
||||
check::krate(self, &compiler, target.target, Mode::Librustc)
|
||||
}
|
||||
|
||||
DistDocs { stage } => dist::docs(self, stage, target.target),
|
||||
DistMingw { _dummy } => dist::mingw(self, target.target),
|
||||
DistRustc { stage } => dist::rustc(self, stage, target.target),
|
||||
DistStd { compiler } => dist::std(self, &compiler, target.target),
|
||||
DistSrc { _dummy } => dist::rust_src(self),
|
||||
|
||||
DebuggerScripts { stage } => {
|
||||
let compiler = Compiler::new(stage, target.target);
|
||||
dist::debugger_scripts(self,
|
||||
&self.sysroot(&compiler),
|
||||
target.target);
|
||||
}
|
||||
|
||||
AndroidCopyLibs { compiler } => {
|
||||
check::android_copy_libs(self, &compiler, target.target);
|
||||
}
|
||||
|
||||
// pseudo-steps
|
||||
Dist { .. } |
|
||||
Doc { .. } |
|
||||
CheckTarget { .. } |
|
||||
Check { .. } => {}
|
||||
}
|
||||
}
|
||||
step::run(self);
|
||||
}
|
||||
|
||||
/// Updates all git submodules that we have.
|
||||
@ -557,12 +333,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));
|
||||
@ -571,8 +358,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"]));
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -634,6 +423,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",
|
||||
@ -659,12 +449,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
|
||||
@ -802,6 +586,11 @@ impl Build {
|
||||
self.out.join(target).join("llvm")
|
||||
}
|
||||
|
||||
/// Output directory for all documentation for a target
|
||||
fn doc_out(&self, target: &str) -> PathBuf {
|
||||
self.out.join(target).join("doc")
|
||||
}
|
||||
|
||||
/// Returns true if no custom `llvm-config` is set for the specified target.
|
||||
///
|
||||
/// If no custom `llvm-config` was specified then Rust's llvm will be used.
|
||||
@ -866,7 +655,7 @@ impl Build {
|
||||
cmd.env("RUSTC_BOOTSTRAP", "1");
|
||||
// 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", "5c6cf767");
|
||||
cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239");
|
||||
}
|
||||
|
||||
/// Returns the compiler's libdir where it stores the dynamic libraries that
|
||||
@ -928,7 +717,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)
|
||||
@ -969,7 +757,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
|
||||
@ -977,7 +766,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)
|
||||
}
|
||||
|
95
src/bootstrap/metadata.rs
Normal file
95
src/bootstrap/metadata.rs
Normal file
@ -0,0 +1,95 @@
|
||||
// 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.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use build_helper::output;
|
||||
use rustc_serialize::json;
|
||||
|
||||
use {Build, Crate};
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Output {
|
||||
packages: Vec<Package>,
|
||||
resolve: Resolve,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Package {
|
||||
id: String,
|
||||
name: String,
|
||||
source: Option<String>,
|
||||
manifest_path: String,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct Resolve {
|
||||
nodes: Vec<ResolveNode>,
|
||||
}
|
||||
|
||||
#[derive(RustcDecodable)]
|
||||
struct ResolveNode {
|
||||
id: String,
|
||||
dependencies: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn build(build: &mut Build) {
|
||||
build_krate(build, "src/rustc/std_shim");
|
||||
build_krate(build, "src/rustc/test_shim");
|
||||
build_krate(build, "src/rustc");
|
||||
}
|
||||
|
||||
fn build_krate(build: &mut Build, krate: &str) {
|
||||
// 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(krate).join("Cargo.toml"));
|
||||
let output = output(&mut cargo);
|
||||
let output: Output = json::decode(&output).unwrap();
|
||||
let mut id2name = HashMap::new();
|
||||
for package in output.packages {
|
||||
if package.source.is_none() {
|
||||
id2name.insert(package.id, package.name.clone());
|
||||
let mut path = PathBuf::from(package.manifest_path);
|
||||
path.pop();
|
||||
build.crates.insert(package.name.clone(), Crate {
|
||||
build_step: format!("build-crate-{}", package.name),
|
||||
doc_step: format!("doc-crate-{}", package.name),
|
||||
test_step: format!("test-crate-{}", package.name),
|
||||
name: package.name,
|
||||
deps: Vec::new(),
|
||||
path: path,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for node in output.resolve.nodes {
|
||||
let name = match id2name.get(&node.id) {
|
||||
Some(name) => name,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let krate = build.crates.get_mut(name).unwrap();
|
||||
for dep in node.dependencies.iter() {
|
||||
let dep = match id2name.get(dep) {
|
||||
Some(dep) => dep,
|
||||
None => continue,
|
||||
};
|
||||
krate.deps.push(dep.clone());
|
||||
}
|
||||
}
|
||||
}
|
@ -17,41 +17,46 @@ else
|
||||
BOOTSTRAP_ARGS :=
|
||||
endif
|
||||
|
||||
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS)
|
||||
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py
|
||||
|
||||
all:
|
||||
$(Q)$(BOOTSTRAP)
|
||||
$(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS)
|
||||
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
|
||||
|
||||
# Don’t use $(Q) here, always show how to invoke the bootstrap script directly
|
||||
help:
|
||||
$(BOOTSTRAP) --help
|
||||
|
||||
clean:
|
||||
$(Q)$(BOOTSTRAP) --clean
|
||||
$(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS)
|
||||
|
||||
rustc-stage1:
|
||||
$(Q)$(BOOTSTRAP) --step libtest --stage 1
|
||||
$(Q)$(BOOTSTRAP) build --stage 1 src/libtest $(BOOTSTRAP_ARGS)
|
||||
rustc-stage2:
|
||||
$(Q)$(BOOTSTRAP) --step libtest --stage 2
|
||||
$(Q)$(BOOTSTRAP) build --stage 2 src/libtest $(BOOTSTRAP_ARGS)
|
||||
|
||||
docs: doc
|
||||
doc:
|
||||
$(Q)$(BOOTSTRAP) --step doc
|
||||
style:
|
||||
$(Q)$(BOOTSTRAP) --step doc-style
|
||||
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
|
||||
nomicon:
|
||||
$(Q)$(BOOTSTRAP) --step doc-nomicon
|
||||
$(Q)$(BOOTSTRAP) doc src/doc/nomicon $(BOOTSTRAP_ARGS)
|
||||
book:
|
||||
$(Q)$(BOOTSTRAP) --step doc-book
|
||||
$(Q)$(BOOTSTRAP) doc src/doc/book $(BOOTSTRAP_ARGS)
|
||||
standalone-docs:
|
||||
$(Q)$(BOOTSTRAP) --step doc-standalone
|
||||
$(Q)$(BOOTSTRAP) doc src/doc $(BOOTSTRAP_ARGS)
|
||||
check:
|
||||
$(Q)$(BOOTSTRAP) --step check
|
||||
$(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS)
|
||||
check-cargotest:
|
||||
$(Q)$(BOOTSTRAP) --step check-cargotest
|
||||
$(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS)
|
||||
dist:
|
||||
$(Q)$(BOOTSTRAP) --step dist
|
||||
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
|
||||
install:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
$(Q)echo "'sudo make install' is not supported currently."
|
||||
else
|
||||
$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
|
||||
endif
|
||||
tidy:
|
||||
$(Q)$(BOOTSTRAP) --step check-tidy --stage 0
|
||||
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
|
||||
|
||||
.PHONY: dist
|
||||
|
@ -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,15 +81,33 @@ 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());
|
||||
}
|
||||
|
||||
if let Some(ref gdb) = build.config.gdb {
|
||||
need_cmd(gdb.as_ref());
|
||||
} else {
|
||||
build.config.gdb = have_cmd("gdb".as_ref());
|
||||
}
|
||||
|
||||
// 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 +117,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 +132,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 +152,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")
|
||||
}
|
||||
}
|
||||
@ -181,7 +204,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
|
||||
.to_string()
|
||||
})
|
||||
};
|
||||
build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
|
||||
build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
|
||||
if build.lldb_version.is_some() {
|
||||
build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -57,8 +57,7 @@ pub fn cp_r(src: &Path, dst: &Path) {
|
||||
let name = path.file_name().unwrap();
|
||||
let dst = dst.join(name);
|
||||
if t!(f.file_type()).is_dir() {
|
||||
let _ = fs::remove_dir_all(&dst);
|
||||
t!(fs::create_dir(&dst));
|
||||
t!(fs::create_dir_all(&dst));
|
||||
cp_r(&path, &dst);
|
||||
} else {
|
||||
let _ = fs::remove_file(&dst);
|
||||
@ -172,3 +171,21 @@ pub fn dylib_path() -> Vec<PathBuf> {
|
||||
env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// `push` all components to `buf`. On windows, append `.exe` to the last component.
|
||||
pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
|
||||
let (&file, components) = components.split_last().expect("at least one component required");
|
||||
let mut file = file.to_owned();
|
||||
|
||||
if cfg!(windows) {
|
||||
file.push_str(".exe");
|
||||
}
|
||||
|
||||
for c in components {
|
||||
buf.push(c);
|
||||
}
|
||||
|
||||
buf.push(file);
|
||||
|
||||
buf
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
#if __ARM_EABI__
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name) \
|
||||
void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
|
||||
# define COMPILER_RT_ABI
|
||||
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
|
||||
#else
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name)
|
||||
# define COMPILER_RT_ABI
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
/* Returns: a ^ b */
|
||||
|
||||
COMPILER_RT_ABI double
|
||||
double
|
||||
__powidf2(double a, si_int b)
|
||||
{
|
||||
const int recip = b < 0;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
/* Returns: a ^ b */
|
||||
|
||||
COMPILER_RT_ABI float
|
||||
float
|
||||
__powisf2(float a, si_int b)
|
||||
{
|
||||
const int recip = b < 0;
|
||||
|
@ -327,7 +327,7 @@ that takes a reference like so:
|
||||
fn call_with_ref<F>(some_closure:F) -> i32
|
||||
where F: Fn(&i32) -> i32 {
|
||||
|
||||
let mut value = 0;
|
||||
let value = 0;
|
||||
some_closure(&value)
|
||||
}
|
||||
```
|
||||
@ -340,14 +340,15 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32
|
||||
where F: Fn(&'a i32) -> i32 {
|
||||
```
|
||||
|
||||
However this presents a problem in our case. When you specify the explicit
|
||||
lifetime on a function it binds that lifetime to the *entire* scope of the function
|
||||
instead of just the invocation scope of our closure. This means that the borrow checker
|
||||
will see a mutable reference in the same lifetime as our immutable reference and fail
|
||||
to compile.
|
||||
However, this presents a problem in our case. When a function has an explicit
|
||||
lifetime parameter, that lifetime must be at least as long as the *entire*
|
||||
call to that function. The borrow checker will complain that `value` doesn't
|
||||
live long enough, because it is only in scope after its declaration inside the
|
||||
function body.
|
||||
|
||||
In order to say that we only need the lifetime to be valid for the invocation scope
|
||||
of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
|
||||
What we need is a closure that can borrow its argument only for its own
|
||||
invocation scope, not for the outer function's scope. In order to say that,
|
||||
we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
|
||||
|
||||
```ignore
|
||||
fn call_with_ref<F>(some_closure:F) -> i32
|
||||
@ -362,7 +363,7 @@ expect.
|
||||
fn call_with_ref<F>(some_closure:F) -> i32
|
||||
where F: for<'a> Fn(&'a i32) -> i32 {
|
||||
|
||||
let mut value = 0;
|
||||
let value = 0;
|
||||
some_closure(&value)
|
||||
}
|
||||
```
|
||||
@ -510,12 +511,11 @@ fn factory() -> Box<Fn(i32) -> i32> {
|
||||
|
||||
Box::new(|x| x + num)
|
||||
}
|
||||
# fn main() {
|
||||
|
||||
let f = factory();
|
||||
|
||||
let answer = f(1);
|
||||
assert_eq!(6, answer);
|
||||
# }
|
||||
```
|
||||
|
||||
There’s just one last problem:
|
||||
@ -540,12 +540,11 @@ fn factory() -> Box<Fn(i32) -> i32> {
|
||||
|
||||
Box::new(move |x| x + num)
|
||||
}
|
||||
fn main() {
|
||||
|
||||
let f = factory();
|
||||
|
||||
let answer = f(1);
|
||||
assert_eq!(6, answer);
|
||||
}
|
||||
```
|
||||
|
||||
By making the inner closure a `move Fn`, we create a new stack frame for our
|
||||
|
@ -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:
|
||||
|
@ -111,41 +111,40 @@ unofficial locations.
|
||||
Note that this table can be expanded over time, this isn't the exhaustive set of
|
||||
tier 3 platforms that will ever be!
|
||||
|
||||
## Installing on Linux or Mac
|
||||
## Installing Rust
|
||||
|
||||
If we're on Linux or a Mac, all we need to do is open a terminal and type this:
|
||||
All you need to do on Unix systems like Linux and macOS is open a
|
||||
terminal and type this:
|
||||
|
||||
```bash
|
||||
$ curl -sSf https://static.rust-lang.org/rustup.sh | sh
|
||||
$ curl https://sh.rustup.rs -sSf | sh
|
||||
```
|
||||
|
||||
This will download a script, and start the installation. If it all goes well,
|
||||
you’ll see this appear:
|
||||
It will download a script, and start the installation. If everything
|
||||
goes well, you’ll see this appear:
|
||||
|
||||
```text
|
||||
Rust is ready to roll.
|
||||
Rust is installed now. Great!
|
||||
```
|
||||
|
||||
From here, press `y` for ‘yes’, and then follow the rest of the prompts.
|
||||
Installing on Windows is nearly as easy: download and run
|
||||
[rustup-init.exe]. It will start the installation in a console and
|
||||
present the above message on success.
|
||||
|
||||
## Installing on Windows
|
||||
For other installation options and information, visit the [install]
|
||||
page of the Rust website.
|
||||
|
||||
If you're on Windows, please download the appropriate [installer][install-page].
|
||||
|
||||
[install-page]: https://www.rust-lang.org/install.html
|
||||
[rustup-init.exe]: https://win.rustup.rs
|
||||
[install]: https://www.rust-lang.org/install.html
|
||||
|
||||
## Uninstalling
|
||||
|
||||
Uninstalling Rust is as easy as installing it. On Linux or Mac, run
|
||||
the uninstall script:
|
||||
Uninstalling Rust is as easy as installing it:
|
||||
|
||||
```bash
|
||||
$ sudo /usr/local/lib/rustlib/uninstall.sh
|
||||
$ rustup self uninstall
|
||||
```
|
||||
|
||||
If we used the Windows installer, we can re-run the `.msi` and it will give us
|
||||
an uninstall option.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If we've got Rust installed, we can open up a shell, and type this:
|
||||
@ -158,20 +157,33 @@ You should see the version number, commit hash, and commit date.
|
||||
|
||||
If you do, Rust has been installed successfully! Congrats!
|
||||
|
||||
If you don't and you're on Windows, check that Rust is in your %PATH% system
|
||||
variable: `$ echo %PATH%`. If it isn't, run the installer again, select "Change"
|
||||
on the "Change, repair, or remove installation" page and ensure "Add to PATH" is
|
||||
installed on the local hard drive. If you need to configure your path manually,
|
||||
you can find the Rust executables in a directory like
|
||||
`"C:\Program Files\Rust stable GNU 1.x\bin"`.
|
||||
If you don't, that probably means that the `PATH` environment variable
|
||||
doesn't include Cargo's binary directory, `~/.cargo/bin` on Unix, or
|
||||
`%USERPROFILE%\.cargo\bin` on Windows. This is the directory where
|
||||
Rust development tools live, and most Rust developers keep it in their
|
||||
`PATH` environment variable, which makes it possible to run `rustc` on
|
||||
the command line. Due to differences in operating systems, command
|
||||
shells, and bugs in installation, you may need to restart your shell,
|
||||
log out of the system, or configure `PATH` manually as appropriate for
|
||||
your operating environment.
|
||||
|
||||
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].
|
||||
@ -183,9 +195,7 @@ resources include [the user’s forum][users] and [Stack Overflow][stackoverflow
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
|
||||
This installer also installs a copy of the documentation locally, so we can
|
||||
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
|
||||
On Windows, it's in a `share/doc` directory, inside the directory to which Rust
|
||||
was installed.
|
||||
read it offline. It's only a `rustup doc` away!
|
||||
|
||||
# Hello, world!
|
||||
|
||||
@ -495,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
|
||||
@ -365,7 +362,6 @@ numbers. A bare number like above is actually shorthand for `^0.3.0`,
|
||||
meaning "anything compatible with 0.3.0".
|
||||
If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"`
|
||||
(note the two equal signs).
|
||||
And if we wanted to use the latest version we could use `rand="*"`.
|
||||
We could also use a range of versions.
|
||||
[Cargo’s documentation][cargodoc] contains more details.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)].
|
||||
@ -95,6 +94,7 @@
|
||||
* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
|
||||
* `||` (`expr || expr`): logical or.
|
||||
* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]).
|
||||
* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro].
|
||||
|
||||
## Other Syntax
|
||||
|
||||
@ -159,6 +159,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.
|
||||
@ -207,6 +211,7 @@
|
||||
[Functions]: functions.html
|
||||
[Generics]: generics.html
|
||||
[Iterators]: iterators.html
|
||||
[`try!` macro]: error-handling.html#the-try-macro
|
||||
[Lifetimes]: lifetimes.html
|
||||
[Loops (`for`)]: loops.html#for
|
||||
[Loops (`loop`)]: loops.html#loop
|
||||
|
@ -24,9 +24,11 @@ Cargo will automatically generate a simple test when you make a new project.
|
||||
Here's the contents of `src/lib.rs`:
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
#[test]
|
||||
fn it_works() {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -36,11 +38,11 @@ currently has no body. That's good enough to pass! We can run the tests with
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
@ -56,7 +58,7 @@ for the test we wrote, and another for documentation tests. We'll talk about
|
||||
those later. For now, see this line:
|
||||
|
||||
```text
|
||||
test it_works ... ok
|
||||
test tests::it_works ... ok
|
||||
```
|
||||
|
||||
Note the `it_works`. This comes from the name of our function:
|
||||
@ -89,31 +91,30 @@ run our tests again:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test it_works ... FAILED
|
||||
test tests::it_works ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- it_works stdout ----
|
||||
thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
|
||||
|
||||
---- test::it_works stdout ----
|
||||
thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5
|
||||
|
||||
|
||||
failures:
|
||||
it_works
|
||||
tests::it_works
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
|
||||
thread 'main' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
|
||||
error: test failed
|
||||
```
|
||||
|
||||
Rust indicates that our test failed:
|
||||
|
||||
```text
|
||||
test it_works ... FAILED
|
||||
test tests::it_works ... FAILED
|
||||
```
|
||||
|
||||
And that's reflected in the summary line:
|
||||
@ -159,11 +160,11 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
@ -191,11 +192,11 @@ passes:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
@ -262,8 +263,8 @@ not:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 2 tests
|
||||
test expensive_test ... ignored
|
||||
@ -282,7 +283,7 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`:
|
||||
|
||||
```bash
|
||||
$ cargo test -- --ignored
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test expensive_test ... ok
|
||||
@ -302,8 +303,11 @@ which is why the command is `cargo test -- --ignored`.
|
||||
# The `tests` module
|
||||
|
||||
There is one way in which our existing example is not idiomatic: it's
|
||||
missing the `tests` module. The idiomatic way of writing our example
|
||||
looks like this:
|
||||
missing the `tests` module. You might have noticed this test module was
|
||||
present in the code that was initially generated with `cargo new` but
|
||||
was missing from our last example. Let's explain what this does.
|
||||
|
||||
The idiomatic way of writing our example looks like this:
|
||||
|
||||
```rust,ignore
|
||||
# fn main() {}
|
||||
@ -356,8 +360,8 @@ Note the different `use` line. Now we run our tests:
|
||||
```bash
|
||||
$ cargo test
|
||||
Updating registry `https://github.com/rust-lang/crates.io-index`
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test tests::it_works ... ok
|
||||
@ -380,9 +384,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;
|
||||
@ -404,15 +408,15 @@ Let's run them:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0 (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Running target/lib-c18e7d3494509e74
|
||||
Running target/debug/integration_test-68064b69521c828a
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
@ -490,15 +494,15 @@ Let's run the tests again:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
Compiling adder v0.1.0. (file:///home/you/projects/adder)
|
||||
Running target/debug/deps/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Running target/lib-c18e7d3494509e74
|
||||
Running target/debug/integration_test-68064b69521c828a
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
|
@ -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?
|
||||
|
@ -2479,8 +2479,6 @@ The currently implemented features of the reference compiler are:
|
||||
* - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
|
||||
(e.g. `extern "vectorcall" func fn_();`)
|
||||
|
||||
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
|
||||
|
||||
* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention
|
||||
(e.g. `extern "sysv64" func fn_();`)
|
||||
|
||||
@ -2860,8 +2858,8 @@ assert_eq!(x, y);
|
||||
|
||||
### Unary operator expressions
|
||||
|
||||
Rust defines the following unary operators. They are all written as prefix operators,
|
||||
before the expression they apply to.
|
||||
Rust defines the following unary operators. With the exception of `?`, they are
|
||||
all written as prefix operators, before the expression they apply to.
|
||||
|
||||
* `-`
|
||||
: Negation. Signed integer types and floating-point types support negation. It
|
||||
@ -2890,6 +2888,10 @@ before the expression they apply to.
|
||||
If the `&` or `&mut` operators are applied to an rvalue, a
|
||||
temporary value is created; the lifetime of this temporary value
|
||||
is defined by [syntactic rules](#temporary-lifetimes).
|
||||
* `?`
|
||||
: Propagating errors if applied to `Err(_)` and unwrapping if
|
||||
applied to `Ok(_)`. Only works on the `Result<T, E>` type,
|
||||
and written in postfix notation.
|
||||
|
||||
### Binary operator expressions
|
||||
|
||||
@ -3109,10 +3111,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) {
|
||||
@ -3122,6 +3126,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
|
||||
@ -3750,6 +3757,21 @@ The special type `Self` has a meaning within traits and impls. In a trait defini
|
||||
to an implicit type parameter representing the "implementing" type. In an impl,
|
||||
it is an alias for the implementing type. For example, in:
|
||||
|
||||
```
|
||||
pub trait From<T> {
|
||||
fn from(T) -> Self;
|
||||
}
|
||||
|
||||
impl From<i32> for String {
|
||||
fn from(x: i32) -> Self {
|
||||
x.to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The notation `Self` in the impl refers to the implementing type: `String`. In another
|
||||
example:
|
||||
|
||||
```
|
||||
trait Printable {
|
||||
fn make_string(&self) -> String;
|
||||
@ -3958,6 +3980,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*.
|
||||
@ -4008,9 +4040,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>) {}
|
||||
}
|
||||
```
|
||||
|
||||
@ -4063,6 +4095,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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
@ -60,74 +36,120 @@ use core::{isize, usize};
|
||||
use core::convert::From;
|
||||
use heap::deallocate;
|
||||
|
||||
/// A soft limit on the amount of references that may be made to an `Arc`.
|
||||
///
|
||||
/// Going above this limit will abort your program (although not
|
||||
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
|
||||
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 +163,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 +232,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 +251,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 +277,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 +317,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 +345,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 +400,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 +426,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 +485,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 +510,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 +571,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 +645,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 +708,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 +723,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 +740,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 +758,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 +807,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 +842,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 +866,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 +875,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 +912,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 +923,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 +940,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 +948,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 +956,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 +977,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 +994,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 +1011,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 +1028,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 +1036,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 +1080,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 +1140,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.
|
||||
|
@ -12,12 +12,12 @@
|
||||
|
||||
//! Single-threaded reference-counting pointers.
|
||||
//!
|
||||
//! The type [`Rc<T>`][rc] provides shared ownership of a value, 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 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.
|
||||
//!
|
||||
//! Shared pointers in Rust disallow mutation by default, and `Rc` is no
|
||||
//! 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].
|
||||
//!
|
||||
@ -44,8 +44,9 @@
|
||||
//! functions][assoc], called using function-like syntax:
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::rc::Rc;
|
||||
//! # let my_rc = Rc::new(());
|
||||
//! use std::rc::Rc;
|
||||
//! let my_rc = Rc::new(());
|
||||
//!
|
||||
//! Rc::downgrade(&my_rc);
|
||||
//! ```
|
||||
//!
|
||||
@ -229,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>,
|
||||
@ -252,7 +254,6 @@ struct RcBox<T: ?Sized> {
|
||||
/// 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`.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T: ?Sized> {
|
||||
ptr: Shared<RcBox<T>>,
|
||||
@ -295,10 +296,13 @@ impl<T> Rc<T> {
|
||||
|
||||
/// Returns the contained value, if the `Rc` has exactly one strong reference.
|
||||
///
|
||||
/// Otherwise, an `Err` is returned with the same `Rc` that was passed in.
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
@ -332,7 +336,11 @@ impl<T> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether `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
|
||||
///
|
||||
@ -358,6 +366,31 @@ 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`][weak] pointer to this value.
|
||||
///
|
||||
@ -583,8 +616,10 @@ impl<T: ?Sized> Drop for Rc<T> {
|
||||
/// Drops the `Rc`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
/// count reaches zero then the only other references (if any) are `Weak`,
|
||||
/// so we `drop` 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
|
||||
///
|
||||
@ -873,7 +908,6 @@ impl<T> From<T> for Rc<T> {
|
||||
///
|
||||
/// [rc]: struct.Rc.html
|
||||
/// [downgrade]: struct.Rc.html#method.downgrade
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
ptr: Shared<RcBox<T>>,
|
||||
|
@ -27,6 +27,20 @@ fn main() {
|
||||
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").expect("NUM_JOBS was not set")));
|
||||
.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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ 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;
|
||||
@ -133,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 {
|
||||
@ -154,24 +155,58 @@ 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 (chunk, new_capacity);
|
||||
let (chunk, mut new_capacity);
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
if last_chunk.storage.double_in_place() {
|
||||
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();
|
||||
new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
loop {
|
||||
new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
if new_capacity >= currently_used_cap + n {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let elem_size = cmp::max(1, mem::size_of::<T>());
|
||||
new_capacity = cmp::max(1, PAGE / elem_size);
|
||||
new_capacity = cmp::max(n, PAGE / elem_size);
|
||||
}
|
||||
chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
@ -302,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);
|
||||
}
|
||||
|
@ -1033,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;
|
||||
|
||||
@ -1048,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> {
|
||||
@ -1056,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,9 +14,10 @@
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::Deref;
|
||||
use core::ops::{Add, AddAssign, Deref};
|
||||
|
||||
use fmt;
|
||||
use string::String;
|
||||
|
||||
use self::Cow::*;
|
||||
|
||||
@ -86,16 +87,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>
|
||||
@ -146,7 +160,10 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
|
||||
match *self {
|
||||
Borrowed(borrowed) => {
|
||||
*self = Owned(borrowed.to_owned());
|
||||
self.to_mut()
|
||||
match *self {
|
||||
Borrowed(..) => unreachable!(),
|
||||
Owned(ref mut owned) => owned,
|
||||
}
|
||||
}
|
||||
Owned(ref mut owned) => owned,
|
||||
}
|
||||
@ -270,3 +287,61 @@ impl<'a, T: ?Sized + ToOwned> AsRef<T> for Cow<'a, T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.14.0")]
|
||||
impl<'a> Add<&'a str> for Cow<'a, str> {
|
||||
type Output = Cow<'a, str>;
|
||||
|
||||
#[inline]
|
||||
fn add(mut self, rhs: &'a str) -> Self::Output {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.14.0")]
|
||||
impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
|
||||
type Output = Cow<'a, str>;
|
||||
|
||||
#[inline]
|
||||
fn add(mut self, rhs: Cow<'a, str>) -> Self::Output {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.14.0")]
|
||||
impl<'a> AddAssign<&'a str> for Cow<'a, str> {
|
||||
fn add_assign(&mut self, rhs: &'a str) {
|
||||
if self.is_empty() {
|
||||
*self = Cow::Borrowed(rhs)
|
||||
} else if rhs.is_empty() {
|
||||
return;
|
||||
} else {
|
||||
if let Cow::Borrowed(lhs) = *self {
|
||||
let mut s = String::with_capacity(lhs.len() + rhs.len());
|
||||
s.push_str(lhs);
|
||||
*self = Cow::Owned(s);
|
||||
}
|
||||
self.to_mut().push_str(rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "cow_add", since = "1.14.0")]
|
||||
impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
|
||||
fn add_assign(&mut self, rhs: Cow<'a, str>) {
|
||||
if self.is_empty() {
|
||||
*self = rhs
|
||||
} else if rhs.is_empty() {
|
||||
return;
|
||||
} else {
|
||||
if let Cow::Borrowed(lhs) = *self {
|
||||
let mut s = String::with_capacity(lhs.len() + rhs.len());
|
||||
s.push_str(lhs);
|
||||
*self = Cow::Owned(s);
|
||||
}
|
||||
self.to_mut().push_str(&rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 := '+' | '-'
|
||||
|
@ -50,9 +50,9 @@
|
||||
#![feature(specialization)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(step_by)]
|
||||
#![feature(trusted_len)]
|
||||
#![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();
|
||||
@ -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]
|
||||
@ -1895,10 +1904,10 @@ impl<'a> FromIterator<String> for Cow<'a, str> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Into<Vec<u8>> for String {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.into_bytes()
|
||||
#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")]
|
||||
impl From<String> for Vec<u8> {
|
||||
fn from(string : String) -> Vec<u8> {
|
||||
string.into_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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")]
|
||||
|
||||
@ -68,7 +75,7 @@ use core::cmp::Ordering;
|
||||
use core::fmt;
|
||||
use core::hash::{self, Hash};
|
||||
use core::intrinsics::{arith_offset, assume};
|
||||
use core::iter::{FromIterator, FusedIterator};
|
||||
use core::iter::{FromIterator, FusedIterator, TrustedLen};
|
||||
use core::mem;
|
||||
use core::ops::{Index, IndexMut};
|
||||
use core::ops;
|
||||
@ -76,10 +83,9 @@ use core::ptr;
|
||||
use core::ptr::Shared;
|
||||
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 +111,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 +143,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 +164,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 +181,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 +197,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 +327,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 +364,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 +378,8 @@ impl<T> Vec<T> {
|
||||
/// that nothing else uses the pointer after calling this
|
||||
/// function.
|
||||
///
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -471,11 +496,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 +703,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 +778,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 +811,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 +963,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
|
||||
///
|
||||
/// ```
|
||||
@ -1089,26 +1244,7 @@ impl<T: Clone> Vec<T> {
|
||||
/// ```
|
||||
#[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
|
||||
pub fn extend_from_slice(&mut self, other: &[T]) {
|
||||
self.reserve(other.len());
|
||||
|
||||
// Unsafe code so this can be optimised to a memcpy (or something
|
||||
// similarly fast) when T is Copy. LLVM is easily confused, so any
|
||||
// extra operations during the loop can prevent this optimisation.
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let ptr = self.get_unchecked_mut(len) as *mut T;
|
||||
// Use SetLenOnDrop to work around bug where compiler
|
||||
// may not realize the store through `ptr` trough self.set_len()
|
||||
// don't alias.
|
||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||
|
||||
for i in 0..other.len() {
|
||||
ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone());
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
// len set by scope guard
|
||||
}
|
||||
self.extend(other.iter().cloned())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1156,90 +1292,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1531,19 +1586,25 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> {
|
||||
impl<T> Extend<T> for Vec<T> {
|
||||
#[inline]
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
<Self as SpecExtend<I>>::spec_extend(self, iter);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: IntoIterator> SpecExtend<I> for Vec<I::Item> {
|
||||
default fn spec_extend(&mut self, iter: I) {
|
||||
self.extend_desugared(iter.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SpecExtend<Vec<T>> for Vec<T> {
|
||||
fn spec_extend(&mut self, ref mut other: Vec<T>) {
|
||||
self.append(other);
|
||||
trait IsTrustedLen : Iterator {
|
||||
fn trusted_len(&self) -> Option<usize> { None }
|
||||
}
|
||||
impl<I> IsTrustedLen for I where I: Iterator { }
|
||||
|
||||
impl<I> IsTrustedLen for I where I: TrustedLen
|
||||
{
|
||||
fn trusted_len(&self) -> Option<usize> {
|
||||
let (low, high) = self.size_hint();
|
||||
if let Some(high_value) = high {
|
||||
debug_assert_eq!(low, high_value,
|
||||
"TrustedLen iterator's size hint is not exact: {:?}",
|
||||
(low, high));
|
||||
}
|
||||
high
|
||||
}
|
||||
}
|
||||
|
||||
@ -1554,16 +1615,30 @@ impl<T> Vec<T> {
|
||||
// for item in iterator {
|
||||
// self.push(item);
|
||||
// }
|
||||
while let Some(element) = iterator.next() {
|
||||
let len = self.len();
|
||||
if len == self.capacity() {
|
||||
let (lower, _) = iterator.size_hint();
|
||||
self.reserve(lower.saturating_add(1));
|
||||
}
|
||||
if let Some(additional) = iterator.trusted_len() {
|
||||
self.reserve(additional);
|
||||
unsafe {
|
||||
ptr::write(self.get_unchecked_mut(len), element);
|
||||
// NB can't overflow since we would have had to alloc the address space
|
||||
self.set_len(len + 1);
|
||||
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
|
||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||
for element in iterator {
|
||||
ptr::write(ptr, element);
|
||||
ptr = ptr.offset(1);
|
||||
// NB can't overflow since we would have had to alloc the address space
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while let Some(element) = iterator.next() {
|
||||
let len = self.len();
|
||||
if len == self.capacity() {
|
||||
let (lower, _) = iterator.size_hint();
|
||||
self.reserve(lower.saturating_add(1));
|
||||
}
|
||||
unsafe {
|
||||
ptr::write(self.get_unchecked_mut(len), element);
|
||||
// NB can't overflow since we would have had to alloc the address space
|
||||
self.set_len(len + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1572,7 +1647,7 @@ 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());
|
||||
self.extend(iter.into_iter().map(|&x| x))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1705,6 +1780,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 +1838,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 +1852,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 +1871,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();
|
||||
@ -1889,6 +1971,9 @@ impl<T> ExactSizeIterator for IntoIter<T> {}
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<T> FusedIterator for IntoIter<T> {}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<T> TrustedLen for IntoIter<T> {}
|
||||
|
||||
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
|
||||
impl<T: Clone> Clone for IntoIter<T> {
|
||||
fn clone(&self) -> IntoIter<T> {
|
||||
@ -1930,7 +2015,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 +2029,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 +2037,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 +2059,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")]
|
||||
|
@ -743,16 +743,8 @@ impl<T> VecDeque<T> {
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -780,20 +772,10 @@ impl<T> VecDeque<T> {
|
||||
#[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")]
|
||||
|
@ -299,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]
|
||||
|
141
src/libcollectionstest/cow_str.rs
Normal file
141
src/libcollectionstest/cow_str.rs
Normal file
@ -0,0 +1,141 @@
|
||||
// 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.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
// check that Cow<'a, str> implements addition
|
||||
#[test]
|
||||
fn check_cow_add_cow() {
|
||||
let borrowed1 = Cow::Borrowed("Hello, ");
|
||||
let borrowed2 = Cow::Borrowed("World!");
|
||||
let borrow_empty = Cow::Borrowed("");
|
||||
|
||||
let owned1: Cow<str> = Cow::Owned(String::from("Hi, "));
|
||||
let owned2: Cow<str> = Cow::Owned(String::from("Rustaceans!"));
|
||||
let owned_empty: Cow<str> = Cow::Owned(String::new());
|
||||
|
||||
assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone());
|
||||
assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone());
|
||||
|
||||
assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone());
|
||||
assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone());
|
||||
|
||||
if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_cow_add_str() {
|
||||
let borrowed = Cow::Borrowed("Hello, ");
|
||||
let borrow_empty = Cow::Borrowed("");
|
||||
|
||||
let owned: Cow<str> = Cow::Owned(String::from("Hi, "));
|
||||
let owned_empty: Cow<str> = Cow::Owned(String::new());
|
||||
|
||||
assert_eq!("Hello, World!", borrowed.clone() + "World!");
|
||||
|
||||
assert_eq!("Hi, World!", owned.clone() + "World!");
|
||||
|
||||
if let Cow::Owned(_) = borrowed.clone() + "" {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
if let Cow::Owned(_) = owned_empty.clone() + "Hello, " {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_cow_add_assign_cow() {
|
||||
let mut borrowed1 = Cow::Borrowed("Hello, ");
|
||||
let borrowed2 = Cow::Borrowed("World!");
|
||||
let borrow_empty = Cow::Borrowed("");
|
||||
|
||||
let mut owned1: Cow<str> = Cow::Owned(String::from("Hi, "));
|
||||
let owned2: Cow<str> = Cow::Owned(String::from("Rustaceans!"));
|
||||
let owned_empty: Cow<str> = Cow::Owned(String::new());
|
||||
|
||||
let mut s = borrowed1.clone();
|
||||
s += borrow_empty.clone();
|
||||
assert_eq!("Hello, ", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
let mut s = borrow_empty.clone();
|
||||
s += borrowed1.clone();
|
||||
assert_eq!("Hello, ", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
let mut s = borrowed1.clone();
|
||||
s += owned_empty.clone();
|
||||
assert_eq!("Hello, ", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
let mut s = owned_empty.clone();
|
||||
s += borrowed1.clone();
|
||||
assert_eq!("Hello, ", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
|
||||
owned1 += borrowed2;
|
||||
borrowed1 += owned2;
|
||||
|
||||
assert_eq!("Hi, World!", owned1);
|
||||
assert_eq!("Hello, Rustaceans!", borrowed1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_cow_add_assign_str() {
|
||||
let mut borrowed = Cow::Borrowed("Hello, ");
|
||||
let borrow_empty = Cow::Borrowed("");
|
||||
|
||||
let mut owned: Cow<str> = Cow::Owned(String::from("Hi, "));
|
||||
let owned_empty: Cow<str> = Cow::Owned(String::new());
|
||||
|
||||
let mut s = borrowed.clone();
|
||||
s += "";
|
||||
assert_eq!("Hello, ", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
let mut s = borrow_empty.clone();
|
||||
s += "World!";
|
||||
assert_eq!("World!", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
let mut s = owned_empty.clone();
|
||||
s += "World!";
|
||||
assert_eq!("World!", s);
|
||||
if let Cow::Owned(_) = s {
|
||||
panic!("Adding empty strings to a borrow should note allocate");
|
||||
}
|
||||
|
||||
owned += "World!";
|
||||
borrowed += "World!";
|
||||
|
||||
assert_eq!("Hi, World!", owned);
|
||||
assert_eq!("Hello, World!", borrowed);
|
||||
}
|
@ -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)]
|
||||
@ -34,10 +36,13 @@ extern crate rustc_unicode;
|
||||
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;
|
||||
mod cow_str;
|
||||
mod enum_set;
|
||||
mod fmt;
|
||||
mod linked_list;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,12 @@ impl Sources {
|
||||
|
||||
fn main() {
|
||||
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")]
|
||||
|
@ -351,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() {
|
||||
|
@ -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] {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
//!
|
||||
@ -245,6 +248,80 @@ impl Ordering {
|
||||
Greater => Less,
|
||||
}
|
||||
}
|
||||
|
||||
/// Chains two orderings.
|
||||
///
|
||||
/// Returns `self` when it's not `Equal`. Otherwise returns `other`.
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ordering_chaining)]
|
||||
///
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let result = Ordering::Equal.then(Ordering::Less);
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
///
|
||||
/// let result = Ordering::Less.then(Ordering::Equal);
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
///
|
||||
/// let result = Ordering::Less.then(Ordering::Greater);
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
///
|
||||
/// let result = Ordering::Equal.then(Ordering::Equal);
|
||||
/// assert_eq!(result, Ordering::Equal);
|
||||
///
|
||||
/// let x: (i64, i64, i64) = (1, 2, 7);
|
||||
/// let y: (i64, i64, i64) = (1, 5, 3);
|
||||
/// let result = x.0.cmp(&y.0).then(x.1.cmp(&y.1)).then(x.2.cmp(&y.2));
|
||||
///
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
/// ```
|
||||
#[unstable(feature = "ordering_chaining", issue = "37053")]
|
||||
pub fn then(self, other: Ordering) -> Ordering {
|
||||
match self {
|
||||
Equal => other,
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Chains the ordering with the given function.
|
||||
///
|
||||
/// Returns `self` when it's not `Equal`. Otherwise calls `f` and returns
|
||||
/// the result.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ordering_chaining)]
|
||||
///
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let result = Ordering::Equal.then_with(|| Ordering::Less);
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
///
|
||||
/// let result = Ordering::Less.then_with(|| Ordering::Equal);
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
///
|
||||
/// let result = Ordering::Less.then_with(|| Ordering::Greater);
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
///
|
||||
/// let result = Ordering::Equal.then_with(|| Ordering::Equal);
|
||||
/// assert_eq!(result, Ordering::Equal);
|
||||
///
|
||||
/// let x: (i64, i64, i64) = (1, 2, 7);
|
||||
/// let y: (i64, i64, i64) = (1, 5, 3);
|
||||
/// let result = x.0.cmp(&y.0).then_with(|| x.1.cmp(&y.1)).then_with(|| x.2.cmp(&y.2));
|
||||
///
|
||||
/// assert_eq!(result, Ordering::Less);
|
||||
/// ```
|
||||
#[unstable(feature = "ordering_chaining", issue = "37053")]
|
||||
pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering {
|
||||
match self {
|
||||
Equal => f(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
|
||||
@ -703,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
|
||||
|
@ -145,7 +145,7 @@ pub trait AsMut<T: ?Sized> {
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - `[From<T>][From] for U` implies `Into<U> for T`
|
||||
/// - [`From<T>`][From]` for U` implies `Into<U> for T`
|
||||
/// - [`into()`] is reflexive, which means that `Into<T> for T` is implemented
|
||||
///
|
||||
/// [`TryInto`]: trait.TryInto.html
|
||||
@ -178,14 +178,14 @@ pub trait Into<T>: Sized {
|
||||
/// ```
|
||||
/// # Generic impls
|
||||
///
|
||||
/// - `From<T> for U` implies `[Into<U>] for T`
|
||||
/// - `From<T> for U` implies [`Into<U>`]` for T`
|
||||
/// - [`from()`] is reflexive, which means that `From<T> for T` is implemented
|
||||
///
|
||||
/// [`TryFrom`]: trait.TryFrom.html
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [Into<U>]: trait.Into.html
|
||||
/// [`Into<U>`]: trait.Into.html
|
||||
/// [`from()`]: trait.From.html#tymethod.from
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait From<T>: Sized {
|
||||
|
@ -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.
|
||||
@ -796,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;
|
||||
@ -807,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 {
|
||||
@ -924,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(()) }
|
||||
@ -1032,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)?;
|
||||
@ -1362,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
|
||||
@ -1435,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]))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1574,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) }
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
@ -90,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
|
||||
@ -98,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`?
|
||||
///
|
||||
@ -127,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.
|
||||
@ -151,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) {
|
||||
@ -189,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) {
|
||||
|
@ -14,12 +14,18 @@
|
||||
|
||||
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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SipHasher13 {
|
||||
hasher: Hasher<Sip13Rounds>,
|
||||
@ -29,7 +35,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SipHasher24 {
|
||||
hasher: Hasher<Sip24Rounds>,
|
||||
@ -39,9 +46,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
|
||||
@ -51,7 +55,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SipHasher(SipHasher24);
|
||||
|
||||
@ -78,70 +83,68 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
pub fn new() -> SipHasher {
|
||||
SipHasher::new_with_keys(0, 0)
|
||||
}
|
||||
@ -149,7 +152,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
|
||||
SipHasher(SipHasher24::new_with_keys(key0, key1))
|
||||
}
|
||||
@ -159,7 +163,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
pub fn new() -> SipHasher13 {
|
||||
SipHasher13::new_with_keys(0, 0)
|
||||
}
|
||||
@ -167,7 +172,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
|
||||
SipHasher13 {
|
||||
hasher: Hasher::new_with_keys(key0, key1)
|
||||
@ -179,7 +185,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
pub fn new() -> SipHasher24 {
|
||||
SipHasher24::new_with_keys(0, 0)
|
||||
}
|
||||
@ -187,7 +194,8 @@ 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")]
|
||||
#[rustc_deprecated(since = "1.13.0",
|
||||
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
|
||||
SipHasher24 {
|
||||
hasher: Hasher::new_with_keys(key0, key1)
|
||||
@ -225,6 +233,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")]
|
||||
@ -267,6 +306,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();
|
||||
@ -276,19 +330,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.
|
||||
@ -297,7 +348,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);
|
||||
@ -306,7 +357,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;
|
||||
}
|
||||
|
||||
|
62
src/libcore/internal_macros.rs
Normal file
62
src/libcore/internal_macros.rs
Normal file
@ -0,0 +1,62 @@
|
||||
// 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.
|
||||
|
||||
|
||||
// implements the unary operator "op &T"
|
||||
// based on "op T" where T is expected to be `Copy`able
|
||||
macro_rules! forward_ref_unop {
|
||||
(impl $imp:ident, $method:ident for $t:ty) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> $imp for &'a $t {
|
||||
type Output = <$t as $imp>::Output;
|
||||
|
||||
#[inline]
|
||||
fn $method(self) -> <$t as $imp>::Output {
|
||||
$imp::$method(*self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// implements binary operators "&T op U", "T op &U", "&T op &U"
|
||||
// based on "T op U" where T and U are expected to be `Copy`able
|
||||
macro_rules! forward_ref_binop {
|
||||
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> $imp<$u> for &'a $t {
|
||||
type Output = <$t as $imp<$u>>::Output;
|
||||
|
||||
#[inline]
|
||||
fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
|
||||
$imp::$method(*self, other)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> $imp<&'a $u> for $t {
|
||||
type Output = <$t as $imp<$u>>::Output;
|
||||
|
||||
#[inline]
|
||||
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
|
||||
$imp::$method(self, *other)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, 'b> $imp<&'a $u> for &'b $t {
|
||||
type Output = <$t as $imp<$u>>::Output;
|
||||
|
||||
#[inline]
|
||||
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
|
||||
$imp::$method(*self, *other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user