diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e7041dcddc..ea9f2c1943 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ always work, and sometimes it's hard to know what to search for, so consider thi extra credit. We won't mind if you accidentally file a duplicate report. Similarly, to help others who encountered the bug find your issue, -consider filing an issue with with a descriptive title, which contains information that might be unique to it. +consider filing an issue with a descriptive title, which contains information that might be unique to it. This can be the language or compiler feature used, the conditions that trigger the bug, or part of the error message if there is any. An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**. @@ -142,7 +142,7 @@ file. If you still have a `config.mk` file in your directory - from ### Building [building]: #building -A default configuration shall use around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB. +A default configuration requires around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB. Dependencies - [build dependencies](README.md#building-from-source) diff --git a/README.md b/README.md index 19ef96fae0..da6788824b 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Read ["Installation"] from [The Book]. 3. Build and install: ```sh + $ git submodule update --init --recursive --progress $ ./x.py build && sudo ./x.py install ``` @@ -119,7 +120,7 @@ shell with: > python x.py build ``` -Currently building Rust only works with some known versions of Visual Studio. If +Currently, building Rust only works with some known versions of Visual Studio. If you have a more recent version installed the build system doesn't understand then you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. @@ -133,7 +134,7 @@ python x.py build [specifying-an-abi]: #specifying-an-abi Each specific ABI can also be used from either environment (for example, using -the GNU ABI in powershell) by using an explicit build triple. The available +the GNU ABI in PowerShell) by using an explicit build triple. The available Windows build triples are: - GNU ABI (using GCC) - `i686-pc-windows-gnu` @@ -179,7 +180,7 @@ the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will [notes]: #notes Since the Rust compiler is written in Rust, it must be built by a -precompiled "snapshot" version of itself (made in an earlier state of +precompiled "snapshot" version of itself (made in an earlier stage of development). As such, source builds require a connection to the Internet, to fetch snapshots, and an OS that can execute the available snapshot binaries. diff --git a/RELEASES.md b/RELEASES.md index f249f774b8..503ce7ede0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,13 +1,144 @@ -Version 1.27.2 (2018-07-20) +Version 1.28.0 (2018-08-02) =========================== +Language +-------- +- [The `#[repr(transparent)]` attribute is now stable.][51562] This attribute + allows a Rust newtype wrapper (`struct NewType(T);`) to be represented as + the inner type across Foreign Function Interface (FFI) boundaries. +- [The keywords `pure`, `sizeof`, `alignof`, and `offsetof` have been unreserved + and can now be used as identifiers.][51196] +- [The `GlobalAlloc` trait and `#[global_allocator]` attribute are now + stable.][51241] This will allow users to specify a global allocator for + their program. +- [Unit test functions marked with the `#[test]` attribute can now return + `Result<(), E: Debug>` in addition to `()`.][51298] +- [The `lifetime` specifier for `macro_rules!` is now stable.][50385] This + allows macros to easily target lifetimes. + +Compiler +-------- +- [The `s` and `z` optimisation levels are now stable.][50265] These optimisations + prioritise making smaller binary sizes. `z` is the same as `s` with the + exception that it does not vectorise loops, which typically results in an even + smaller binary. +- [The short error format is now stable.][49546] Specified with + `--error-format=short` this option will provide a more compressed output of + rust error messages. +- [Added a lint warning when you have duplicated `macro_export`s.][50143] +- [Reduced the number of allocations in the macro parser.][50855] This can + improve compile times of macro heavy crates on average by 5%. + +Libraries +--------- +- [Implemented `Default` for `&mut str`.][51306] +- [Implemented `From` for all integer and unsigned number types.][50554] +- [Implemented `Extend` for `()`.][50234] +- [The `Debug` implementation of `time::Duration` should now be more easily + human readable.][50364] Previously a `Duration` of one second would printed as + `Duration { secs: 1, nanos: 0 }` and will now be printed as `1s`. +- [Implemented `From<&String>` for `Cow`, `From<&Vec>` for `Cow<[T]>`, + `From>` for `CString`, `From, From, From<&CString>` + for `Cow`, `From, From, From<&OsString>` for + `Cow`, `From<&PathBuf>` for `Cow`, and `From>` + for `PathBuf`.][50170] +- [Implemented `Shl` and `Shr` for `Wrapping` + and `Wrapping`.][50465] +- [`DirEntry::metadata` now uses `fstatat` instead of `lstat` when + possible.][51050] This can provide up to a 40% speed increase. +- [Improved error messages when using `format!`.][50610] + +Stabilized APIs +--------------- +- [`Iterator::step_by`] +- [`Path::ancestors`] +- [`btree_map::Entry::or_default`] +- [`fmt::Alignment`] +- [`hash_map::Entry::or_default`] +- [`iter::repeat_with`] +- [`num::NonZeroUsize`] +- [`num::NonZeroU128`] +- [`num::NonZeroU16`] +- [`num::NonZeroU32`] +- [`num::NonZeroU64`] +- [`num::NonZeroU8`] +- [`ops::RangeBounds`] +- [`slice::SliceIndex`] +- [`slice::from_mut`] +- [`slice::from_ref`] +- [`{Any + Send + Sync}::downcast_mut`] +- [`{Any + Send + Sync}::downcast_ref`] +- [`{Any + Send + Sync}::is`] + +Cargo +----- +- [Cargo will now no longer allow you to publish crates with build scripts that + modify the `src` directory.][cargo/5584] The `src` directory in a crate should be + considered to be immutable. + +Misc +---- +- [The `suggestion_applicability` field in `rustc`'s json output is now + stable.][50486] This will allow dev tools to check whether a code suggestion + would apply to them. + Compatibility Notes ------------------- +- [Rust will no longer consider trait objects with duplicated constraints to + have implementations.][51276] For example the below code will now fail + to compile. + ```rust + trait Trait {} -- The borrow checker was fixed to avoid potential unsoundness when using - match ergonomics: [#52213][52213]. + impl Trait + Send { + fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` + } -[52213]: https://github.com/rust-lang/rust/issues/52213 + impl Trait + Send + Send { + fn test(&self) { println!("two"); } + } + ``` + +[49546]: https://github.com/rust-lang/rust/pull/49546/ +[50143]: https://github.com/rust-lang/rust/pull/50143/ +[50170]: https://github.com/rust-lang/rust/pull/50170/ +[50234]: https://github.com/rust-lang/rust/pull/50234/ +[50265]: https://github.com/rust-lang/rust/pull/50265/ +[50364]: https://github.com/rust-lang/rust/pull/50364/ +[50385]: https://github.com/rust-lang/rust/pull/50385/ +[50465]: https://github.com/rust-lang/rust/pull/50465/ +[50486]: https://github.com/rust-lang/rust/pull/50486/ +[50554]: https://github.com/rust-lang/rust/pull/50554/ +[50610]: https://github.com/rust-lang/rust/pull/50610/ +[50855]: https://github.com/rust-lang/rust/pull/50855/ +[51050]: https://github.com/rust-lang/rust/pull/51050/ +[51196]: https://github.com/rust-lang/rust/pull/51196/ +[51200]: https://github.com/rust-lang/rust/pull/51200/ +[51241]: https://github.com/rust-lang/rust/pull/51241/ +[51276]: https://github.com/rust-lang/rust/pull/51276/ +[51298]: https://github.com/rust-lang/rust/pull/51298/ +[51306]: https://github.com/rust-lang/rust/pull/51306/ +[51562]: https://github.com/rust-lang/rust/pull/51562/ +[cargo/5584]: https://github.com/rust-lang/cargo/pull/5584/ +[`Iterator::step_by`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.step_by +[`Path::ancestors`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.ancestors +[`btree_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default +[`fmt::Alignment`]: https://doc.rust-lang.org/std/fmt/enum.Alignment.html +[`hash_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default +[`iter::repeat_with`]: https://doc.rust-lang.org/std/iter/fn.repeat_with.html +[`num::NonZeroUsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html +[`num::NonZeroU128`]: https://doc.rust-lang.org/std/num/struct.NonZeroU128.html +[`num::NonZeroU16`]: https://doc.rust-lang.org/std/num/struct.NonZeroU16.html +[`num::NonZeroU32`]: https://doc.rust-lang.org/std/num/struct.NonZeroU32.html +[`num::NonZeroU64`]: https://doc.rust-lang.org/std/num/struct.NonZeroU64.html +[`num::NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html +[`ops::RangeBounds`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html +[`slice::SliceIndex`]: https://doc.rust-lang.org/std/slice/trait.SliceIndex.html +[`slice::from_mut`]: https://doc.rust-lang.org/std/slice/fn.from_mut.html +[`slice::from_ref`]: https://doc.rust-lang.org/std/slice/fn.from_ref.html +[`{Any + Send + Sync}::downcast_mut`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_mut-2 +[`{Any + Send + Sync}::downcast_ref`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref-2 +[`{Any + Send + Sync}::is`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.is-2 Version 1.27.1 (2018-07-10) =========================== @@ -18,7 +149,7 @@ Security Notes - rustdoc would execute plugins in the /tmp/rustdoc/plugins directory when running, which enabled executing code as some other user on a given machine. This release fixes that vulnerability; you can read - more about this on the [blog][rustdoc-sec]. + more about this on the [blog][rustdoc-sec]. The associated CVE is [CVE-2018-1000622]. Thank you to Red Hat for responsibily disclosing this vulnerability to us. @@ -31,6 +162,7 @@ Compatibility Notes [51415]: https://github.com/rust-lang/rust/issues/51415 [49534]: https://github.com/rust-lang/rust/issues/49534 [rustdoc-sec]: https://blog.rust-lang.org/2018/07/06/security-advisory-for-rustdoc.html +[CVE-2018-1000622]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=%20CVE-2018-1000622 Version 1.27.0 (2018-06-21) ========================== @@ -90,7 +222,6 @@ Stabilized APIs - [`Take::set_limit`] - [`hint::unreachable_unchecked`] - [`os::unix::process::parent_id`] -- [`process::id`] - [`ptr::swap_nonoverlapping`] - [`slice::rsplit_mut`] - [`slice::rsplit`] @@ -100,6 +231,7 @@ Cargo ----- - [`cargo-metadata` now includes `authors`, `categories`, `keywords`, `readme`, and `repository` fields.][cargo/5386] +- [`cargo-metadata` now includes a package's `metadata` table.][cargo/5360] - [Added the `--target-dir` optional argument.][cargo/5393] This allows you to specify a different directory than `target` for placing compilation artifacts. - [Cargo will be adding automatic target inference for binaries, benchmarks, @@ -149,6 +281,7 @@ Compatibility Notes [cargo/5203]: https://github.com/rust-lang/cargo/pull/5203/ [cargo/5335]: https://github.com/rust-lang/cargo/pull/5335/ [cargo/5359]: https://github.com/rust-lang/cargo/pull/5359/ +[cargo/5360]: https://github.com/rust-lang/cargo/pull/5360/ [cargo/5386]: https://github.com/rust-lang/cargo/pull/5386/ [cargo/5393]: https://github.com/rust-lang/cargo/pull/5393/ [`DoubleEndedIterator::rfind`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfind @@ -165,17 +298,15 @@ Compatibility Notes [`Option::filter`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.filter [`String::replace_range`]: https://doc.rust-lang.org/std/string/struct.String.html#method.replace_range [`Take::set_limit`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.set_limit +[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html +[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html +[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html +[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html [`slice::rsplit_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit_mut [`slice::rsplit`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit [`slice::swap_with_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.swap_with_slice [`arch::x86_64`]: https://doc.rust-lang.org/std/arch/x86_64/index.html [`arch::x86`]: https://doc.rust-lang.org/std/arch/x86/index.html -[`fs::read`]: -[`fs::write`]: -[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html -[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html -[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html -[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html [“The Rustc book”]: https://doc.rust-lang.org/rustc @@ -199,6 +330,7 @@ Tools - [RLS now works on Windows][50646] - [Rustfmt stopped badly formatting text in some cases][rustfmt/2695] + Compatibility Notes -------- @@ -222,7 +354,7 @@ Language - [Closures now implement `Copy` and/or `Clone` if all captured variables implement either or both traits.][49299] - [The inclusive range syntax e.g. `for x in 0..=10` is now stable.][47813] -- [Stablise `'_`. The underscore lifetime can be used anywhere where a +- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere where a lifetime can be elided.][49458] - [`impl Trait` is now stable allowing you to have abstract types in returns or in function parameters.][49255] e.g. `fn foo() -> impl Iterator` or @@ -313,7 +445,6 @@ Cargo - [Cargo will now output path to custom commands when `-v` is passed with `--list`][cargo/5041] - [The Cargo binary version is now the same as the Rust version][cargo/5083] -- [`Cargo.lock` files are now included in published crates.][cargo/5093] Misc ---- @@ -417,7 +548,6 @@ Compatibility Notes [`String::retain`]: https://doc.rust-lang.org/std/string/struct.String.html#method.retain [cargo/5041]: https://github.com/rust-lang/cargo/pull/5041 [cargo/5083]: https://github.com/rust-lang/cargo/pull/5083 -[cargo/5093]: https://github.com/rust-lang/cargo/pull/5093 Version 1.25.0 (2018-03-29) @@ -425,7 +555,7 @@ Version 1.25.0 (2018-03-29) Language -------- -- [Stabilised `#[repr(align(x))]`.][47006] [RFC 1358] +- [The `#[repr(align(x))]` attribute is now stable.][47006] [RFC 1358] - [You can now use nested groups of imports.][47948] e.g. `use std::{fs::File, io::Read, path::{Path, PathBuf}};` - [You can now have `|` at the start of a match arm.][47947] e.g. diff --git a/config.toml.example b/config.toml.example index 34fcc755b3..feb55d57ef 100644 --- a/config.toml.example +++ b/config.toml.example @@ -76,6 +76,10 @@ # passed to prefer linking to shared libraries. #link-shared = false +# On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass +# with clang-cl, so this is special in that it only compiles LLVM with clang-cl +#clang-cl = '/path/to/clang-cl.exe' + # ============================================================================= # General build configuration options # ============================================================================= @@ -275,6 +279,9 @@ # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true +# Whether to always use incremental compilation when building rustc +#incremental = false + # Build rustc with experimental parallelization #experimental-parallel-queries = false @@ -294,9 +301,9 @@ # desired in distributions, for example. #rpath = true -# Suppresses extraneous output from tests to ensure the output of the test -# harness is relatively clean. -#quiet-tests = false +# Emits extraneous output from tests to ensure that failures of the test +# harness are debuggable just from logfiles. +#verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag) or # with debuginfo (the -g flag) diff --git a/git-commit-hash b/git-commit-hash index 026bf9f068..8e89520a36 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -58cc626de3301192d5d8c6dcbde43b5b44211ae2 \ No newline at end of file +0aaa819fea00a6bf2b1303b9eb47f142f099cf5a \ No newline at end of file diff --git a/src/Cargo.lock b/src/Cargo.lock index ea2d146ff6..6f39947d7f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -20,7 +20,7 @@ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", @@ -79,15 +79,15 @@ dependencies = [ [[package]] name = "assert_cli" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -105,7 +105,7 @@ name = "backtrace" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -114,11 +114,12 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.16" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -145,7 +146,7 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -183,11 +184,6 @@ dependencies = [ name = "build_helper" version = "0.1.0" -[[package]] -name = "bytecount" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.2.2" @@ -195,13 +191,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.28.0" +version = "0.29.0" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.16.0", + "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.17.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -233,25 +229,13 @@ dependencies = [ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cargo_metadata" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargo_metadata" version = "0.5.4" @@ -270,7 +254,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.10" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -278,6 +262,23 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chalk-engine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "chalk-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "chrono" version = "0.4.1" @@ -305,15 +306,17 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.195" +version = "0.0.202" dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.195", + "clippy_lints 0.0.202", "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -325,15 +328,16 @@ version = "0.2.0" [[package]] name = "clippy_lints" -version = "0.0.195" +version = "0.0.202" dependencies = [ + "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -344,7 +348,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.0.197" +version = "0.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -354,7 +358,7 @@ dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -368,7 +372,7 @@ name = "cmake" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -399,7 +403,7 @@ dependencies = [ name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -416,7 +420,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -437,7 +441,7 @@ dependencies = [ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -454,24 +458,21 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "crates-io" -version = "0.16.0" +version = "0.17.0" dependencies = [ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -533,7 +534,7 @@ name = "curl" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.5 (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.40 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -545,10 +546,10 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", @@ -557,6 +558,11 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "datafrog" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "debug_unreachable" version = "0.1.1" @@ -571,12 +577,12 @@ version = "0.1.0" [[package]] name = "derive-new" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -584,11 +590,6 @@ name = "diff" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "difference" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "difference" version = "2.0.0" @@ -628,7 +629,7 @@ dependencies = [ [[package]] name = "ena" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -968,6 +969,16 @@ name = "is-match" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "isatty" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.7.8" @@ -1019,7 +1030,7 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.39.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1064,9 +1075,9 @@ name = "libgit2-sys" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1091,7 +1102,7 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1130,7 +1141,7 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1189,7 +1200,7 @@ dependencies = [ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1207,12 +1218,20 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "minifier" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1308,7 +1327,7 @@ name = "openssl-sys" version = "0.9.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1435,6 +1454,16 @@ name = "pkg-config" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "polonius-engine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1449,14 +1478,6 @@ dependencies = [ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "proc-macro2" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "proc-macro2" version = "0.3.6" @@ -1479,7 +1500,7 @@ dependencies = [ name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1508,14 +1529,6 @@ name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "0.5.1" @@ -1526,16 +1539,17 @@ dependencies = [ [[package]] name = "racer" -version = "2.0.13" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1621,6 +1635,18 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" version = "0.5.5" @@ -1629,6 +1655,14 @@ dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex-syntax" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "remote-test-client" version = "0.1.0" @@ -1647,43 +1681,45 @@ dependencies = [ [[package]] name = "rls" -version = "0.127.0" +version = "0.128.0" dependencies = [ - "cargo 0.28.0", + "cargo 0.29.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.205 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.6.1", + "rustfmt-nightly 0.8.2", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-analysis" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1695,7 +1731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-data" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1706,7 +1742,7 @@ dependencies = [ [[package]] name = "rls-rustc" -version = "0.2.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1724,7 +1760,7 @@ name = "rls-vfs" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1744,105 +1780,117 @@ dependencies = [ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", + "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-ap-arena" +version = "156.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_data_structures" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_target" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-serialize" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-syntax" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "121.0.0" +version = "156.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-arena 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1851,6 +1899,14 @@ name = "rustc-demangle" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-hash" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-main" version = "0.0.0" @@ -1859,6 +1915,27 @@ dependencies = [ "rustc_target 0.0.0", ] +[[package]] +name = "rustc-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -1868,6 +1945,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "rustc_allocator" version = "0.0.0" dependencies = [ + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", @@ -1909,6 +1987,52 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_codegen_llvm" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_allocator 0.0.0", + "rustc_apfloat 0.0.0", + "rustc_codegen_utils 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_errors 0.0.0", + "rustc_incremental 0.0.0", + "rustc_llvm 0.0.0", + "rustc_mir 0.0.0", + "rustc_platform_intrinsics 0.0.0", + "rustc_target 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_codegen_utils" +version = "0.0.0" +dependencies = [ + "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_incremental 0.0.0", + "rustc_mir 0.0.0", + "rustc_target 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + [[package]] name = "rustc_cratesio_shim" version = "0.0.0" @@ -1922,10 +2046,13 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1941,8 +2068,10 @@ dependencies = [ "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", + "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_incremental 0.0.0", @@ -1956,8 +2085,8 @@ dependencies = [ "rustc_save_analysis 0.0.0", "rustc_target 0.0.0", "rustc_traits 0.0.0", - "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", + "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", "syntax_ext 0.0.0", @@ -2008,7 +2137,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -2049,9 +2178,11 @@ dependencies = [ "arena 0.0.0", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", @@ -2131,7 +2262,7 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2157,6 +2288,7 @@ name = "rustc_traits" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -2165,52 +2297,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "rustc_trans" -version = "0.0.0" -dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", - "rustc_apfloat 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_incremental 0.0.0", - "rustc_llvm 0.0.0", - "rustc_mir 0.0.0", - "rustc_platform_intrinsics 0.0.0", - "rustc_target 0.0.0", - "rustc_trans_utils 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_trans_utils" -version = "0.0.0" -dependencies = [ - "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_incremental 0.0.0", - "rustc_mir 0.0.0", - "rustc_target 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - [[package]] name = "rustc_tsan" version = "0.0.0" @@ -2228,7 +2314,6 @@ name = "rustc_typeck" version = "0.0.0" dependencies = [ "arena 0.0.0", - "fmt_macros 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", @@ -2239,10 +2324,19 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_version" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustdoc" version = "0.0.0" dependencies = [ + "minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2260,10 +2354,11 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2271,38 +2366,28 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "0.6.1" +version = "0.8.2" dependencies = [ - "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "same-file" -version = "0.1.3" -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)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2332,15 +2417,6 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "semver" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "semver" version = "0.9.0" @@ -2418,21 +2494,6 @@ name = "siphasher" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "skeptic" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "smallvec" version = "0.6.0" @@ -2461,6 +2522,7 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", @@ -2543,16 +2605,6 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.13.1" @@ -2611,6 +2663,7 @@ dependencies = [ name = "syntax_pos" version = "0.0.0" dependencies = [ + "arena 0.0.0", "rustc_data_structures 0.0.0", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", @@ -2675,7 +2728,7 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2779,14 +2832,6 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "toml" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "toml" version = "0.4.6" @@ -2936,16 +2981,6 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "walkdir" -version = "1.0.7" -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)", - "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "walkdir" version = "2.1.4" @@ -3023,46 +3058,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930" +"checksum assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da59dbd8df54562665b925b427221ceda9b771408cb8a6cbd2125d3b001330b" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" -"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" +"checksum backtrace-sys 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5fd343a2466c4603f76f38de264bc0526cffc7fa38ba52fb9f13237eccc1ced2" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" -"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537" "checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3" -"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" +"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a146c19172c7eea48ea55a7123ac95da786639bc665097f1e14034ee5f1d8699" +"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)" = "ee3b543abb36b1557180d41dd3758581254644d85d021df7f8f8cb395054581c" +"checksum clippy_lints 0.0.205 (registry+https://github.com/rust-lang/crates.io-index)" = "1dcb837d7510bf9e4e3b6f470c450c6d25e61116db5503a6f565bb6283860622" "checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" "checksum compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "608d9d3ccc45b63bf337d2ff5e65def5a5a52c187122232509f6b72707f61b1b" -"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" -"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" +"checksum core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7caa6cb9e76ddddbea09a03266d6b3bc98cd41e9fb9b017c473e7cca593ec25" +"checksum core-foundation-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2a53cce0ddcf7e7e1f998738d757d5a3bf08bf799a180e50ebe50d298f52f5a" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" "checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0" -"checksum curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f7738d877ec81040305d5bb91976ac594f564f5e455dc02a29a23c1d00fe6f" +"checksum curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71c63a540a9ee4e15e56c3ed9b11a2f121239b9f6d7b7fe30f616e048148df9a" +"checksum datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d724bf4ffe77cdceeecd461009b5f8d9e23c5d645d68bedb4586bf43e7e142" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" -"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71" +"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" -"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f" -"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834" +"checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621" "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "be27f8ea102a7182093a80d98f0b78623b580eda8791cbe8e2345fe6e57567a6" @@ -3096,13 +3131,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" "checksum ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "245bea0ba52531a3739cb8ba99f8689eda13d7faf8c36b6a73ce4421aab42588" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" +"checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522" "checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" "checksum jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "60af5f849e1981434e4a31d3d782c4774ae9b434ce55b101a96ecfd09147e8be" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4cdd5e52d71aca47050e5b25f03082609c63a1e76b7362ebdd010895b3f854" +"checksum languageserver-types 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "017cf5ade4be5ebeb06277ccd281c268dbd2e0801128d3992b4b4057f34dd432" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" @@ -3121,6 +3157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "26f3e36a4db1981b16567e4abfd6ddc3641bc9b950bdc868701f656bf9b74bdd" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" "checksum nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa" @@ -3146,17 +3183,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b6b0a7f5f4278b991ffd14abce1d01b013121ad297460237ef0a2f08d43201" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" -"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" -"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d" +"checksum racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "e713729f45f12df5c5e182d39506766f76c09133fb661d3622e0ddf8078911c2" "checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" @@ -3165,30 +3201,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" +"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb" +"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46" +"checksum rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da9794cd1f80f2cb888c00641a32f9855d0226c954ee31cef145784914c7142e" "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2" -"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" -"checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" +"checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988" +"checksum rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c8c09117ae2887baaa4b17fe1cb572f9b22e4d2c6a5cda04093d8b366b0be99" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" -"checksum rustc-ap-rustc_cratesio_shim 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ef7efbe957ee3b1ebecb6a260f7b0bad2286c9c20da614eab669a74da5b5fa7" -"checksum rustc-ap-rustc_data_structures 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b168f552c0d3ee3cca0e1ec693649d05d6ea4c0203fe292edc40f82db96dac" -"checksum rustc-ap-rustc_errors 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c5fc02aa44c4d4d42c9d1e026f526f9d2db01dd1387161c9bcae468a7e147c2" -"checksum rustc-ap-rustc_target 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e309c073c612668f0a7b87719073b904c22e8e6df99ee40309eef7f5ec2e14f8" -"checksum rustc-ap-serialize 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef7721a58ba33a1aa296b527348cefc6170c66ce2bbc248b8ea0b2b49ebbc457" -"checksum rustc-ap-syntax 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d22e392afa778785b1ce243b006b7fde6708cd8dbc332a33821169626c4e5a6" -"checksum rustc-ap-syntax_pos 121.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d897ddf75e2d60a4c78edccf84c072b0905ee0acb6dd566882aaca2103594419" +"checksum rustc-ap-arena 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83e91a01cd6c5a9e4f68c2b5c81b62b172aa9e00fc2fec862c0899e3fac1fd32" +"checksum rustc-ap-rustc_cratesio_shim 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8ea8fadc5d66c1527771816e83f7e7599543bd2e1583e279855370ab2f18e5" +"checksum rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "742ba74bc7d0f3ded56148329650f137fa5b90f7f0ecc4b4952150f32c66b147" +"checksum rustc-ap-rustc_errors 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3714046c6f8c1c259822aefcca21b1862710a6cec24fd34c0796117f074c6769" +"checksum rustc-ap-rustc_target 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b982c4517c18080895b06149ce8aa8279fd013f629030bb7a179bfcff6d74ef2" +"checksum rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27c7700595bff1a64ddb6f593c69db3f6d66b76b059b26137236c7e21e36db70" +"checksum rustc-ap-syntax 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6482d98c8be57d3cfe55dab744dd1a87f8462dc2ea0a8a4960f7bb1565be049" +"checksum rustc-ap-syntax_pos 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20af5e200b61a3e5ba4f58ed3cbd7593569faf8f0956d5233f4f27fee51b4c81" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" +"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" +"checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306" +"checksum rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40f06724db71e18d68b3b946fdf890ca8c921d9edccc1404fdfdb537b0d12649" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85" -"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a" +"checksum rustfix 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9da3cf9b79dc889a2c9879643f26d7a53e37e9361c7566b7d2787d5ace0d8396" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" "checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" "checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248" @@ -3199,7 +3240,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" -"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" "checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" @@ -3210,7 +3250,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545" "checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" @@ -3219,7 +3258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" "checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c" +"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" @@ -3228,7 +3267,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" -"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" @@ -3249,7 +3287,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" diff --git a/src/Cargo.toml b/src/Cargo.toml index 35858ee286..47fbe779c5 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -4,7 +4,7 @@ members = [ "rustc", "libstd", "libtest", - "librustc_trans", + "librustc_codegen_llvm", "tools/cargotest", "tools/clippy", "tools/compiletest", @@ -40,6 +40,13 @@ members = [ "tools/rls/test_data/workspace_symbol", ] +# Curiously, libtest will segfault if compiled with opt-level=3 +# with some versions of XCode: https://github.com/rust-lang/rust/issues/50867 +[profile.release] +opt-level = 2 +[profile.bench] +opt-level = 2 + # These options are controlled from our rustc wrapper script, so turn them off # here and have them controlled elsewhere. [profile.dev] @@ -57,11 +64,8 @@ debug-assertions = false [patch."https://github.com/rust-lang/cargo"] cargo = { path = "tools/cargo" } -[patch.crates-io] +[patch."https://github.com/rust-lang-nursery/rustfmt"] # Similar to Cargo above we want the RLS to use a vendored version of `rustfmt` # that we're shipping as well (to ensure that the rustfmt in RLS and the -# `rustfmt` executable are the same exact vesion). Unlike Cargo, however, the -# RLS depends on `rustfmt` from crates.io, so we put this in a `[patch]` section -# for crates.io +# `rustfmt` executable are the same exact vesion). rustfmt-nightly = { path = "tools/rustfmt" } -clippy_lints = { path = "tools/clippy/clippy_lints" } diff --git a/src/README.md b/src/README.md index 690ab674c6..6da4944c39 100644 --- a/src/README.md +++ b/src/README.md @@ -6,7 +6,7 @@ This directory contains the source code of the rust project, including: For more information on how various parts of the compiler work, see the [rustc guide]. Their is also useful content in the following READMEs, which are gradually being moved over to the guide: -- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/maps +- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query - https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph - https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints - https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2f9c4e148a..af33ebf3c4 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -28,6 +28,11 @@ name = "sccache-plus-cl" path = "bin/sccache-plus-cl.rs" test = false +[[bin]] +name = "llvm-config-wrapper" +path = "bin/llvm-config-wrapper.rs" +test = false + [dependencies] build_helper = { path = "../build_helper" } cmake = "0.1.23" diff --git a/src/bootstrap/bin/llvm-config-wrapper.rs b/src/bootstrap/bin/llvm-config-wrapper.rs new file mode 100644 index 0000000000..b1703f8c72 --- /dev/null +++ b/src/bootstrap/bin/llvm-config-wrapper.rs @@ -0,0 +1,27 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The sheer existence of this file is an awful hack. See the comments in +// `src/bootstrap/native.rs` for why this is needed when compiling LLD. + +use std::env; +use std::process::{self, Stdio, Command}; +use std::io::{self, Write}; + +fn main() { + let real_llvm_config = env::var_os("LLVM_CONFIG_REAL").unwrap(); + let mut cmd = Command::new(real_llvm_config); + cmd.args(env::args().skip(1)).stderr(Stdio::piped()); + let output = cmd.output().expect("failed to spawn llvm-config"); + let stdout = String::from_utf8_lossy(&output.stdout); + print!("{}", stdout.replace("\\", "/")); + io::stdout().flush().unwrap(); + process::exit(output.status.code().unwrap_or(1)); +} diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 3f97accaa4..4607ca5cf9 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -268,6 +268,15 @@ fn main() { if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); } + + if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { + if s == "true" { + cmd.arg("-C").arg("target-feature=+crt-static"); + } + if s == "false" { + cmd.arg("-C").arg("target-feature=-crt-static"); + } + } } if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() { @@ -288,7 +297,12 @@ fn main() { } if verbose > 1 { - eprintln!("rustc command: {:?}", cmd); + eprintln!( + "rustc command: {:?}={:?} {:?}", + bootstrap::util::dylib_path_var(), + env::join_paths(&dylib_path).unwrap(), + cmd, + ); eprintln!("sysroot: {:?}", sysroot); eprintln!("libdir: {:?}", libdir); } diff --git a/src/bootstrap/bin/sccache-plus-cl.rs b/src/bootstrap/bin/sccache-plus-cl.rs index 8584014d48..0a20ac7e49 100644 --- a/src/bootstrap/bin/sccache-plus-cl.rs +++ b/src/bootstrap/bin/sccache-plus-cl.rs @@ -16,8 +16,8 @@ use std::process::{self, Command}; fn main() { let target = env::var("SCCACHE_TARGET").unwrap(); // Locate the actual compiler that we're invoking - env::remove_var("CC"); - env::remove_var("CXX"); + env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); + env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) .out_dir("/") @@ -39,6 +39,12 @@ fn main() { cmd.arg(arg); } + if let Ok(s) = env::var("SCCACHE_EXTRA_ARGS") { + for s in s.split_whitespace() { + cmd.arg(s); + } + } + let status = cmd.status().expect("failed to spawn"); process::exit(status.code().unwrap_or(2)) } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 487440becf..28f5192f2c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -489,7 +489,7 @@ class RustBuild(object): """ return os.path.join(self.build_dir, self.build, "stage0") - def get_toml(self, key): + def get_toml(self, key, section=None): """Returns the value of the given key in config.toml, otherwise returns None >>> rb = RustBuild() @@ -501,12 +501,29 @@ class RustBuild(object): >>> rb.get_toml("key3") is None True + + Optionally also matches the section the key appears in + + >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"' + >>> rb.get_toml('key', 'a') + 'value1' + >>> rb.get_toml('key', 'b') + 'value2' + >>> rb.get_toml('key', 'c') is None + True """ + + cur_section = None for line in self.config_toml.splitlines(): + section_match = re.match(r'^\s*\[(.*)\]\s*$', line) + if section_match is not None: + cur_section = section_match.group(1) + match = re.match(r'^{}\s*=(.*)$'.format(key), line) if match is not None: value = match.group(1) - return self.get_string(value) or value.strip() + if section is None or section == cur_section: + return self.get_string(value) or value.strip() return None def cargo(self): @@ -589,7 +606,17 @@ class RustBuild(object): env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" - env["RUSTFLAGS"] = "-Cdebuginfo=2" + env["RUSTFLAGS"] = "-Cdebuginfo=2 " + + build_section = "target.{}".format(self.build_triple()) + target_features = [] + if self.get_toml("crt-static", build_section) == "true": + target_features += ["+crt-static"] + elif self.get_toml("crt-static", build_section) == "false": + target_features += ["-crt-static"] + if target_features: + env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " " + env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9c35cb7f50..ec7eebd1d0 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -11,6 +11,7 @@ use std::any::Any; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; +use std::collections::HashMap; use std::env; use std::fmt::Debug; use std::fs; @@ -18,26 +19,25 @@ use std::hash::Hash; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::Command; -use std::time::{Instant, Duration}; -use std::collections::HashMap; +use std::time::{Duration, Instant}; -use compile; -use install; -use dist; -use util::{exe, libdir, add_lib_path}; -use {Build, Mode, DocTests}; -use cache::{INTERNER, Interned, Cache}; +use cache::{Cache, Interned, INTERNER}; use check; -use test; -use flags::Subcommand; +use compile; +use dist; use doc; -use tool; +use flags::Subcommand; +use install; use native; +use test; +use tool; +use util::{add_lib_path, exe, libdir}; +use {Build, DocTests, Mode}; pub use Compiler; -use petgraph::Graph; use petgraph::graph::NodeIndex; +use petgraph::Graph; pub struct Builder<'a> { pub build: &'a Build, @@ -111,27 +111,38 @@ struct StepDescription { } #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] -struct PathSet { - set: BTreeSet, +pub enum PathSet { + Set(BTreeSet), + Suite(PathBuf), } impl PathSet { fn empty() -> PathSet { - PathSet { set: BTreeSet::new() } + PathSet::Set(BTreeSet::new()) } fn one>(path: P) -> PathSet { let mut set = BTreeSet::new(); set.insert(path.into()); - PathSet { set } + PathSet::Set(set) } fn has(&self, needle: &Path) -> bool { - self.set.iter().any(|p| p.ends_with(needle)) + match self { + PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)), + PathSet::Suite(_) => false, + } } fn path(&self, builder: &Builder) -> PathBuf { - self.set.iter().next().unwrap_or(&builder.build.src).to_path_buf() + match self { + PathSet::Set(set) => set + .iter() + .next() + .unwrap_or(&builder.build.src) + .to_path_buf(), + PathSet::Suite(path) => PathBuf::from(path), + } } } @@ -151,8 +162,10 @@ impl StepDescription { eprintln!("Skipping {:?} because it is excluded", pathset); return; } else if !builder.config.exclude.is_empty() { - eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset, - self.name, builder.config.exclude); + eprintln!( + "{:?} not skipped for {:?} -- not in {:?}", + pathset, self.name, builder.config.exclude + ); } let hosts = &builder.hosts; @@ -181,14 +194,18 @@ impl StepDescription { } fn run(v: &[StepDescription], builder: &Builder, paths: &[PathBuf]) { - let should_runs = v.iter().map(|desc| { - (desc.should_run)(ShouldRun::new(builder)) - }).collect::>(); + let should_runs = v + .iter() + .map(|desc| (desc.should_run)(ShouldRun::new(builder))) + .collect::>(); // sanity checks on rules for (desc, should_run) in v.iter().zip(&should_runs) { - assert!(!should_run.paths.is_empty(), - "{:?} should have at least one pathset", desc.name); + assert!( + !should_run.paths.is_empty(), + "{:?} should have at least one pathset", + desc.name + ); } if paths.is_empty() { @@ -203,7 +220,10 @@ impl StepDescription { for path in paths { let mut attempted_run = false; for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(pathset) = should_run.pathset_for_path(path) { + if let Some(suite) = should_run.is_suite_path(path) { + attempted_run = true; + desc.maybe_run(builder, suite); + } else if let Some(pathset) = should_run.pathset_for_path(path) { attempted_run = true; desc.maybe_run(builder, pathset); } @@ -250,7 +270,7 @@ impl<'a> ShouldRun<'a> { for krate in self.builder.in_tree_crates(name) { set.insert(PathBuf::from(&krate.path)); } - self.paths.insert(PathSet { set }); + self.paths.insert(PathSet::Set(set)); self } @@ -268,9 +288,20 @@ impl<'a> ShouldRun<'a> { // multiple aliases for the same job pub fn paths(mut self, paths: &[&str]) -> Self { - self.paths.insert(PathSet { - set: paths.iter().map(PathBuf::from).collect(), - }); + self.paths + .insert(PathSet::Set(paths.iter().map(PathBuf::from).collect())); + self + } + + pub fn is_suite_path(&self, path: &Path) -> Option<&PathSet> { + self.paths.iter().find(|pathset| match pathset { + PathSet::Suite(p) => path.starts_with(p), + PathSet::Set(_) => false, + }) + } + + pub fn suite_path(mut self, suite: &str) -> Self { + self.paths.insert(PathSet::Suite(PathBuf::from(suite))); self } @@ -304,40 +335,137 @@ impl<'a> Builder<'a> { }}; } match kind { - Kind::Build => describe!(compile::Std, compile::Test, compile::Rustc, - compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex, - tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest, - tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, - tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, - native::Llvm, tool::Rustfmt, tool::Miri, native::Lld), - Kind::Check => describe!(check::Std, check::Test, check::Rustc, check::CodegenBackend, - check::Rustdoc), - Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass, - test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind, - test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo, - test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps, - test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty, - test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty, - test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, - test::Crate, test::CrateLibrustc, test::CrateRustdoc, test::Linkcheck, - test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck, + Kind::Build => describe!( + compile::Std, + compile::Test, + compile::Rustc, + compile::CodegenBackend, + compile::StartupObjects, + tool::BuildManifest, + tool::Rustbook, + tool::ErrorIndex, + tool::UnstableBookGen, + tool::Tidy, + tool::Linkchecker, + tool::CargoTest, + tool::Compiletest, + tool::RemoteTestServer, + tool::RemoteTestClient, + tool::RustInstaller, + tool::Cargo, + tool::Rls, + tool::Rustdoc, + tool::Clippy, + native::Llvm, + tool::Rustfmt, + tool::Miri, + native::Lld + ), + Kind::Check => describe!( + check::Std, + check::Test, + check::Rustc, + check::CodegenBackend, + check::Rustdoc + ), + Kind::Test => describe!( + test::Tidy, + test::Ui, + test::RunPass, + test::CompileFail, + test::ParseFail, + test::RunFail, + test::RunPassValgrind, + test::MirOpt, + test::Codegen, + test::CodegenUnits, + test::Incremental, + test::Debuginfo, + test::UiFullDeps, + test::RunPassFullDeps, + test::RunFailFullDeps, + test::CompileFailFullDeps, + test::IncrementalFullDeps, + test::Rustdoc, + test::Pretty, + test::RunPassPretty, + test::RunFailPretty, + test::RunPassValgrindPretty, + test::RunPassFullDepsPretty, + test::RunFailFullDepsPretty, + test::Crate, + test::CrateLibrustc, + test::CrateRustdoc, + test::Linkcheck, + test::Cargotest, + test::Cargo, + test::Rls, + test::ErrorIndex, + test::Distcheck, test::RunMakeFullDeps, - test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample, - test::TheBook, test::UnstableBook, test::RustcBook, - test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme, + test::Nomicon, + test::Reference, + test::RustdocBook, + test::RustByExample, + test::TheBook, + test::UnstableBook, + test::RustcBook, + test::Rustfmt, + test::Miri, + test::Clippy, + test::RustdocJS, + test::RustdocTheme, + // Run bootstrap close to the end as it's unlikely to fail + test::Bootstrap, // Run run-make last, since these won't pass without make on Windows - test::RunMake, test::RustdocUi), + test::RunMake, + test::RustdocUi + ), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), - Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, - doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc, - doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample, - doc::RustcBook, doc::CargoBook), - Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc, - dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, - dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended, - dist::HashSign), - Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls, - install::Rustfmt, install::Analysis, install::Src, install::Rustc), + Kind::Doc => describe!( + doc::UnstableBook, + doc::UnstableBookGen, + doc::TheBook, + doc::Standalone, + doc::Std, + doc::Test, + doc::WhitelistedRustc, + doc::Rustc, + doc::Rustdoc, + doc::ErrorIndex, + doc::Nomicon, + doc::Reference, + doc::RustdocBook, + doc::RustByExample, + doc::RustcBook, + doc::CargoBook + ), + Kind::Dist => describe!( + dist::Docs, + dist::RustcDocs, + dist::Mingw, + dist::Rustc, + dist::DebuggerScripts, + dist::Std, + dist::Analysis, + dist::Src, + dist::PlainSourceTarball, + dist::Cargo, + dist::Rls, + dist::Rustfmt, + dist::Extended, + dist::HashSign + ), + Kind::Install => describe!( + install::Docs, + install::Std, + install::Cargo, + install::Rls, + install::Rustfmt, + install::Analysis, + install::Src, + install::Rustc + ), } } @@ -372,8 +500,12 @@ impl<'a> Builder<'a> { } let mut help = String::from("Available paths:\n"); for pathset in should_run.paths { - for path in pathset.set { - help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + if let PathSet::Set(set) = pathset { + set.iter().for_each(|path| { + help.push_str( + format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(), + ) + }) } } Some(help) @@ -405,9 +537,12 @@ impl<'a> Builder<'a> { }; if kind == Kind::Dist { - assert!(!builder.config.test_miri, "Do not distribute with miri enabled.\n\ + assert!( + !builder.config.test_miri, + "Do not distribute with miri enabled.\n\ The distributed libraries would include all MIR (increasing binary size). - The distributed MIR would include validation statements."); + The distributed MIR would include validation statements." + ); } builder @@ -432,7 +567,9 @@ impl<'a> Builder<'a> { /// obtained through this function, since it ensures that they are valid /// (i.e., built and assembled). pub fn compiler(&self, stage: u32, host: Interned) -> Compiler { - self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } }) + self.ensure(compile::Assemble { + target_compiler: Compiler { stage, host }, + }) } pub fn sysroot(&self, compiler: Compiler) -> Interned { @@ -442,7 +579,9 @@ impl<'a> Builder<'a> { /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. pub fn sysroot_libdir( - &self, compiler: Compiler, target: Interned + &self, + compiler: Compiler, + target: Interned, ) -> Interned { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct Libdir { @@ -464,8 +603,12 @@ impl<'a> Builder<'a> { } else { Path::new("lib") }; - let sysroot = builder.sysroot(self.compiler).join(lib) - .join("rustlib").join(self.target).join("lib"); + let sysroot = builder + .sysroot(self.compiler) + .join(lib) + .join("rustlib") + .join(self.target) + .join("lib"); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); INTERNER.intern_path(sysroot) @@ -499,7 +642,7 @@ impl<'a> Builder<'a> { // compiler live next to the compiler and the system will find them // automatically. if cfg!(windows) { - return + return; } add_lib_path(vec![self.rustc_libdir(compiler)], cmd); @@ -510,7 +653,9 @@ impl<'a> Builder<'a> { if compiler.is_snapshot(self) { self.initial_rustc.clone() } else { - self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host)) + self.sysroot(compiler) + .join("bin") + .join(exe("rustc", &compiler.host)) } } @@ -522,12 +667,15 @@ impl<'a> Builder<'a> { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); let compiler = self.compiler(self.top_stage, host); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build)) - .env("CFG_RELEASE_CHANNEL", &self.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(host)) - .env("RUSTDOC_CRATE_VERSION", self.rust_version()) - .env("RUSTC_BOOTSTRAP", "1"); + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env( + "RUSTDOC_LIBDIR", + self.sysroot_libdir(compiler, self.config.build), + ) + .env("CFG_RELEASE_CHANNEL", &self.config.channel) + .env("RUSTDOC_REAL", self.rustdoc(host)) + .env("RUSTDOC_CRATE_VERSION", self.rust_version()) + .env("RUSTC_BOOTSTRAP", "1"); if let Some(linker) = self.linker(host) { cmd.env("RUSTC_TARGET_LINKER", linker); } @@ -541,17 +689,25 @@ impl<'a> Builder<'a> { /// rustc compiler, its output will be scoped by `mode`'s output directory, /// it will pass the `--target` flag for the specified `target`, and will be /// executing the Cargo command `cmd`. - pub fn cargo(&self, - compiler: Compiler, - mode: Mode, - target: Interned, - cmd: &str) -> Command { + pub fn cargo( + &self, + compiler: Compiler, + mode: Mode, + target: Interned, + cmd: &str, + ) -> Command { let mut cargo = Command::new(&self.initial_cargo); let out_dir = self.stage_out(compiler, mode); - cargo.env("CARGO_TARGET_DIR", out_dir) - .arg(cmd) - .arg("--target") - .arg(target); + cargo + .env("CARGO_TARGET_DIR", out_dir) + .arg(cmd); + + if cmd != "install" { + cargo.arg("--target") + .arg(target); + } else { + assert_eq!(target, compiler.host); + } // Set a flag for `check` so that certain build scripts can do less work // (e.g. not building/requiring LLVM). @@ -559,15 +715,22 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } - // If we were invoked from `make` then that's already got a jobserver - // set up for us so no need to tell Cargo about jobs all over again. - if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() { - cargo.arg("-j").arg(self.jobs().to_string()); - } + cargo.arg("-j").arg(self.jobs().to_string()); + // Remove make-related flags to ensure Cargo can correctly set things up + cargo.env_remove("MAKEFLAGS"); + cargo.env_remove("MFLAGS"); // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005 // Force cargo to output binaries with disambiguating hashes in the name - cargo.env("__CARGO_DEFAULT_LIB_METADATA", &self.config.channel); + let metadata = if compiler.stage == 0 { + // Treat stage0 like special channel, whether it's a normal prior- + // release rustc or a local rebuild with the same version, so we + // never mix these libraries by accident. + "bootstrap" + } else { + &self.config.channel + }; + cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata); let stage; if compiler.stage == 0 && self.local_rebuild { @@ -587,8 +750,14 @@ impl<'a> Builder<'a> { } if !extra_args.is_empty() { - cargo.env("RUSTFLAGS", - format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args)); + cargo.env( + "RUSTFLAGS", + format!( + "{} {}", + env::var("RUSTFLAGS").unwrap_or_default(), + extra_args + ), + ); } let want_rustdoc = self.doc_tests != DocTests::No; @@ -599,23 +768,29 @@ impl<'a> Builder<'a> { // // These variables are primarily all read by // src/bootstrap/bin/{rustc.rs,rustdoc.rs} - cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) - .env("RUSTC", self.out.join("bootstrap/debug/rustc")) - .env("RUSTC_REAL", self.rustc(compiler)) - .env("RUSTC_STAGE", stage.to_string()) - .env("RUSTC_DEBUG_ASSERTIONS", - self.config.rust_debug_assertions.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) - .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) - .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) - .env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) { - self.rustdoc(compiler.host) - } else { - PathBuf::from("/path/to/nowhere/rustdoc/not/required") - }) - .env("TEST_MIRI", self.config.test_miri.to_string()) - .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); + cargo + .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) + .env("RUSTC", self.out.join("bootstrap/debug/rustc")) + .env("RUSTC_REAL", self.rustc(compiler)) + .env("RUSTC_STAGE", stage.to_string()) + .env( + "RUSTC_DEBUG_ASSERTIONS", + self.config.rust_debug_assertions.to_string(), + ) + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) + .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) + .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) + .env( + "RUSTDOC_REAL", + if cmd == "doc" || (cmd == "test" && want_rustdoc) { + self.rustdoc(compiler.host) + } else { + PathBuf::from("/path/to/nowhere/rustdoc/not/required") + }, + ) + .env("TEST_MIRI", self.config.test_miri.to_string()) + .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); @@ -627,19 +802,25 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_ERROR_FORMAT", error_format); } if cmd != "build" && cmd != "check" && want_rustdoc { - cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build))); + cargo.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build)); } - if mode == Mode::Tool { + if mode.is_tool() { // Tools like cargo and rls don't get debuginfo by default right now, but this can be // enabled in the config. Adding debuginfo makes them several times larger. if self.config.rust_debuginfo_tools { cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()); - cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()); + cargo.env( + "RUSTC_DEBUGINFO_LINES", + self.config.rust_debuginfo_lines.to_string(), + ); } } else { cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()); - cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()); + cargo.env( + "RUSTC_DEBUGINFO_LINES", + self.config.rust_debuginfo_lines.to_string(), + ); cargo.env("RUSTC_FORCE_UNSTABLE", "1"); // Currently the compiler depends on crates from crates.io, and @@ -665,6 +846,10 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_CRT_STATIC", x.to_string()); } + if let Some(x) = self.crt_static(compiler.host) { + cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string()); + } + // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); @@ -685,12 +870,14 @@ impl<'a> Builder<'a> { // // If LLVM support is disabled we need to use the snapshot compiler to compile // build scripts, as the new compiler doesn't support executables. - if mode == Mode::Libstd || !self.config.llvm_enabled { - cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc) - .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); + if mode == Mode::Std || !self.config.llvm_enabled { + cargo + .env("RUSTC_SNAPSHOT", &self.initial_rustc) + .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); } else { - cargo.env("RUSTC_SNAPSHOT", self.rustc(compiler)) - .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); + cargo + .env("RUSTC_SNAPSHOT", self.rustc(compiler)) + .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); } // Ignore incremental modes except for stage0, since we're @@ -715,7 +902,7 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. - if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) { + if self.config.deny_warnings && !(mode == Mode::Std && stage == 0) { cargo.env("RUSTC_DENY_WARNINGS", "1"); } @@ -726,7 +913,11 @@ impl<'a> Builder<'a> { // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here - if !target.contains("msvc") { + if target.contains("msvc") { + if let Some(ref cl) = self.config.llvm_clang_cl { + cargo.env("CC", cl).env("CXX", cl); + } + } else { let ccache = self.config.ccache.as_ref(); let ccacheify = |s: &Path| { let ccache = match ccache { @@ -744,32 +935,36 @@ impl<'a> Builder<'a> { } }; let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target), &cc) - .env("CC", &cc); + cargo.env(format!("CC_{}", target), &cc).env("CC", &cc); let cflags = self.cflags(target).join(" "); - cargo.env(format!("CFLAGS_{}", target), cflags.clone()) - .env("CFLAGS", cflags.clone()); + cargo + .env(format!("CFLAGS_{}", target), cflags.clone()) + .env("CFLAGS", cflags.clone()); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); - cargo.env(format!("AR_{}", target), ar) - .env("AR", ar) - .env(format!("RANLIB_{}", target), ranlib.clone()) - .env("RANLIB", ranlib); + cargo + .env(format!("AR_{}", target), ar) + .env("AR", ar) + .env(format!("RANLIB_{}", target), ranlib.clone()) + .env("RANLIB", ranlib); } if let Ok(cxx) = self.cxx(target) { let cxx = ccacheify(&cxx); - cargo.env(format!("CXX_{}", target), &cxx) - .env("CXX", &cxx) - .env(format!("CXXFLAGS_{}", target), cflags.clone()) - .env("CXXFLAGS", cflags); + cargo + .env(format!("CXX_{}", target), &cxx) + .env("CXX", &cxx) + .env(format!("CXXFLAGS_{}", target), cflags.clone()) + .env("CXXFLAGS", cflags); } } - if cmd == "build" && mode == Mode::Libstd - && self.config.extended && compiler.is_final_stage(self) + if cmd == "build" + && mode == Mode::Std + && self.config.extended + && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } @@ -803,7 +998,7 @@ impl<'a> Builder<'a> { // default via `-ldylib=winapi_foo`. That is, they're linked with the // `dylib` type with a `winapi_` prefix (so the winapi ones don't // conflict with the system MinGW ones). This consequently means that - // the binaries we ship of things like rustc_trans (aka the rustc_trans + // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm // DLL) when linked against *again*, for example with procedural macros // or plugins, will trigger the propagation logic of `-ldylib`, passing // `-lwinapi_foo` to the linker again. This isn't actually available in @@ -816,7 +1011,7 @@ impl<'a> Builder<'a> { // be resolved because MinGW has the import library. The downside is we // don't get newer functions from Windows, but we don't use any of them // anyway. - if mode != Mode::Tool { + if !mode.is_tool() { cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); } @@ -831,8 +1026,8 @@ impl<'a> Builder<'a> { } if self.config.rust_optimize { - // FIXME: cargo bench does not accept `--release` - if cmd != "bench" { + // FIXME: cargo bench/install do not accept `--release` + if cmd != "bench" && cmd != "install" { cargo.arg("--release"); } } @@ -857,7 +1052,10 @@ impl<'a> Builder<'a> { let mut stack = self.stack.borrow_mut(); for stack_step in stack.iter() { // should skip - if stack_step.downcast_ref::().map_or(true, |stack_step| *stack_step != step) { + if stack_step + .downcast_ref::() + .map_or(true, |stack_step| *stack_step != step) + { continue; } let mut out = String::new(); @@ -873,7 +1071,9 @@ impl<'a> Builder<'a> { { let mut graph = self.graph.borrow_mut(); let parent = self.parent.get(); - let us = *self.graph_nodes.borrow_mut() + let us = *self + .graph_nodes + .borrow_mut() .entry(format!("{:?}", step)) .or_insert_with(|| graph.add_node(format!("{:?}", step))); if let Some(parent) = parent { @@ -892,7 +1092,9 @@ impl<'a> Builder<'a> { { let mut graph = self.graph.borrow_mut(); let parent = self.parent.get(); - let us = *self.graph_nodes.borrow_mut() + let us = *self + .graph_nodes + .borrow_mut() .entry(format!("{:?}", step)) .or_insert_with(|| graph.add_node(format!("{:?}", step))); self.parent.set(Some(us)); @@ -914,10 +1116,12 @@ impl<'a> Builder<'a> { self.parent.set(prev_parent); if self.config.print_step_timings && dur > Duration::from_millis(100) { - println!("[TIMING] {:?} -- {}.{:03}", - step, - dur.as_secs(), - dur.subsec_nanos() / 1_000_000); + println!( + "[TIMING] {:?} -- {}.{:03}", + step, + dur.as_secs(), + dur.subsec_nanos() / 1_000_000 + ); } { @@ -925,7 +1129,11 @@ impl<'a> Builder<'a> { let cur_step = stack.pop().expect("step stack empty"); assert_eq!(cur_step.downcast_ref(), Some(&step)); } - self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)); + self.verbose(&format!( + "{}< {:?}", + " ".repeat(self.stack.borrow().len()), + step + )); self.cache.put(step, out.clone()); out } @@ -933,9 +1141,9 @@ impl<'a> Builder<'a> { #[cfg(test)] mod __test { + use super::*; use config::Config; use std::thread; - use super::*; fn configure(host: &[&str], target: &[&str]) -> Config { let mut config = Config::default_opts(); @@ -944,15 +1152,26 @@ mod __test { config.run_host_only = true; config.dry_run = true; // try to avoid spurious failures in dist where we create/delete each others file - let dir = config.out.join("tmp-rustbuild-tests") - .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); + let dir = config.out.join("tmp-rustbuild-tests").join( + &thread::current() + .name() + .unwrap_or("unknown") + .replace(":", "-"), + ); t!(fs::create_dir_all(&dir)); config.out = dir; config.build = INTERNER.intern_str("A"); - config.hosts = vec![config.build].clone().into_iter() - .chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::>(); - config.targets = config.hosts.clone().into_iter() - .chain(target.iter().map(|s| INTERNER.intern_str(s))).collect::>(); + config.hosts = vec![config.build] + .clone() + .into_iter() + .chain(host.iter().map(|s| INTERNER.intern_str(s))) + .collect::>(); + config.targets = config + .hosts + .clone() + .into_iter() + .chain(target.iter().map(|s| INTERNER.intern_str(s))) + .collect::>(); config } @@ -968,21 +1187,27 @@ mod __test { let a = INTERNER.intern_str("A"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { + assert_eq!( + first(builder.cache.all::()), + &[dist::Docs { stage: 2, host: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: a, - }, - ]); + },] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -995,27 +1220,36 @@ mod __test { let a = INTERNER.intern_str("A"); let b = INTERNER.intern_str("B"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -1028,28 +1262,41 @@ mod __test { let a = INTERNER.intern_str("A"); let b = INTERNER.intern_str("B"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -1063,34 +1310,50 @@ mod __test { let b = INTERNER.intern_str("B"); let c = INTERNER.intern_str("C"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - dist::Docs { stage: 2, host: c }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - dist::Mingw { host: c }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + dist::Docs { stage: 2, host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -1106,31 +1369,40 @@ mod __test { let b = INTERNER.intern_str("B"); let c = INTERNER.intern_str("C"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - dist::Docs { stage: 2, host: c }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - dist::Mingw { host: c }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + dist::Docs { stage: 2, host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ] + ); assert_eq!(first(builder.cache.all::()), &[]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[]); } @@ -1143,87 +1415,109 @@ mod __test { let a = INTERNER.intern_str("A"); let b = INTERNER.intern_str("B"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Std { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Assemble { - target_compiler: Compiler { host: a, stage: 0 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 2 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 2 }, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ] + ); } #[test] @@ -1238,83 +1532,89 @@ mod __test { assert!(!builder.cache.all::().is_empty()); assert!(!builder.cache.all::().is_empty()); - assert_eq!(first(builder.cache.all::()), &[ - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + ] + ); - assert_eq!(first(builder.cache.all::()), &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); } #[test] @@ -1330,84 +1630,93 @@ mod __test { let c = INTERNER.intern_str("C"); assert!(!builder.cache.all::().is_empty()); - assert_eq!(first(builder.cache.all::()), &[ - compile::Assemble { - target_compiler: Compiler { host: a, stage: 0 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 2 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 2 }, - }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); - assert_eq!(first(builder.cache.all::()), &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); } #[test] @@ -1420,6 +1729,8 @@ mod __test { rustc_args: vec![], fail_fast: true, doc_tests: DocTests::No, + bless: false, + compare_mode: None, }; let build = Build::new(config); @@ -1434,14 +1745,15 @@ mod __test { // Ensure we don't build any compiler artifacts. assert!(builder.cache.all::().is_empty()); - assert_eq!(first(builder.cache.all::()), &[ - test::Crate { + assert_eq!( + first(builder.cache.all::()), + &[test::Crate { compiler: Compiler { host, stage: 0 }, target: host, - mode: Mode::Libstd, + mode: Mode::Std, test_kind: test::TestKind::Test, krate: INTERNER.intern_str("std"), - }, - ]); + },] + ); } } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 2718db4cea..a2495f68c1 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.27.2"; +pub const CFG_RELEASE_NUM: &str = "1.28.0"; pub struct GitInfo { inner: Option, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 64354ae29a..b3ccb3cc3c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -40,10 +40,10 @@ impl Step for Std { let target = self.target; let compiler = builder.compiler(0, builder.config.build); - let out_dir = builder.stage_out(compiler, Mode::Libstd); + let out_dir = builder.stage_out(compiler, Mode::Std); builder.clear_if_dirty(&out_dir, &builder.rustc(compiler)); - let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, "check"); std_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); @@ -87,11 +87,11 @@ impl Step for Rustc { let compiler = builder.compiler(0, builder.config.build); let target = self.target; - let stage_out = builder.stage_out(compiler, Mode::Librustc); + let stage_out = builder.stage_out(compiler, Mode::Rustc); builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target)); builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "check"); rustc_cargo(builder, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); @@ -118,7 +118,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc_trans") + run.all_krates("rustc_codegen_llvm") } fn make_run(run: RunConfig) { @@ -137,14 +137,14 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "check"); let features = builder.rustc_features().to_string(); - cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml")); + cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); // We won't build LLVM if it's not available, as it shouldn't affect `check`. - let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); run_cargo(builder, cargo.arg("--features").arg(features), &codegen_backend_stamp(builder, compiler, target, backend), @@ -175,10 +175,10 @@ impl Step for Test { let compiler = builder.compiler(0, builder.config.build); let target = self.target; - let out_dir = builder.stage_out(compiler, Mode::Libtest); + let out_dir = builder.stage_out(compiler, Mode::Test); builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, "check"); test_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); @@ -219,6 +219,7 @@ impl Step for Rustdoc { let mut cargo = prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, target, "check", "src/tools/rustdoc"); @@ -236,7 +237,7 @@ impl Step for Rustdoc { builder.ensure(tool::CleanTools { compiler, target, - mode: Mode::Tool, + cause: Mode::Rustc, }); } } @@ -244,33 +245,33 @@ impl Step for Rustdoc { /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp") + builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp") + builder.cargo_out(compiler, Mode::Test, target).join(".libtest-check.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp") + builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp") } -/// Cargo's output path for librustc_trans in a given stage, compiled by a particular +/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular /// compiler for the specified target and backend. fn codegen_backend_stamp(builder: &Builder, compiler: Compiler, target: Interned, backend: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target) - .join(format!(".librustc_trans-{}-check.stamp", backend)) + builder.cargo_out(compiler, Mode::Codegen, target) + .join(format!(".librustc_codegen_llvm-{}-check.stamp", backend)) } /// Cargo's output path for rustdoc in a given stage, compiled by a particular /// compiler for the specified target. pub fn rustdoc_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Tool, target).join(".rustdoc-check.stamp") + builder.cargo_out(compiler, Mode::ToolRustc, target).join(".rustdoc-check.stamp") } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1248c2b50b..11d9154ba6 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -98,9 +98,9 @@ impl Step for Std { copy_musl_third_party_objects(builder, target, &libdir); } - let out_dir = builder.cargo_out(compiler, Mode::Libstd, target); + let out_dir = builder.cargo_out(compiler, Mode::Std, target); builder.clear_if_dirty(&out_dir, &builder.rustc(compiler)); - let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, "build"); std_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); @@ -240,7 +240,7 @@ impl Step for StdLink { builder.ensure(tool::CleanTools { compiler: target_compiler, target, - mode: Mode::Libstd, + cause: Mode::Std, }); } } @@ -368,9 +368,9 @@ impl Step for Test { return; } - let out_dir = builder.cargo_out(compiler, Mode::Libtest, target); + let out_dir = builder.cargo_out(compiler, Mode::Test, target); builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, "build"); test_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); @@ -431,7 +431,7 @@ impl Step for TestLink { builder.ensure(tool::CleanTools { compiler: target_compiler, target, - mode: Mode::Libtest, + cause: Mode::Test, }); } } @@ -489,11 +489,11 @@ impl Step for Rustc { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); - let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target); + let cargo_out = builder.cargo_out(compiler, Mode::Rustc, target); builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target)); builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build"); rustc_cargo(builder, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); @@ -585,7 +585,7 @@ impl Step for RustcLink { builder.ensure(tool::CleanTools { compiler: target_compiler, target, - mode: Mode::Librustc, + cause: Mode::Rustc, }); } } @@ -603,7 +603,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc_trans") + run.all_krates("rustc_codegen_llvm") } fn make_run(run: RunConfig) { @@ -634,18 +634,18 @@ impl Step for CodegenBackend { return; } - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build"); let mut features = builder.rustc_features().to_string(); cargo.arg("--manifest-path") - .arg(builder.src.join("src/librustc_trans/Cargo.toml")); + .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); - let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target) + let tmp_stamp = builder.cargo_out(compiler, Mode::Codegen, target) .join(".tmp.stamp"); - let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); let files = run_cargo(builder, cargo.arg("--features").arg(features), &tmp_stamp, @@ -656,7 +656,7 @@ impl Step for CodegenBackend { let mut files = files.into_iter() .filter(|f| { let filename = f.file_name().unwrap().to_str().unwrap(); - is_dylib(filename) && filename.contains("rustc_trans-") + is_dylib(filename) && filename.contains("rustc_codegen_llvm-") }); let codegen_backend = match files.next() { Some(f) => f, @@ -697,7 +697,7 @@ pub fn build_codegen_backend(builder: &Builder, compiler.stage, &compiler.host, target, backend)); // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_trans. + // librustc_llvm and librustc_codegen_llvm. if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } @@ -762,7 +762,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, t!(t!(File::open(&stamp)).read_to_string(&mut dylib)); let file = Path::new(&dylib); let filename = file.file_name().unwrap().to_str().unwrap(); - // change `librustc_trans-xxxxxx.so` to `librustc_trans-llvm.so` + // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so` let target_filename = { let dash = filename.find("-").unwrap(); let dot = filename.find(".").unwrap(); @@ -793,29 +793,29 @@ fn copy_lld_to_sysroot(builder: &Builder, /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") + builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") + builder.cargo_out(compiler, Mode::Test, target).join(".libtest.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") + builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp") } -/// Cargo's output path for librustc_trans in a given stage, compiled by a particular +/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular /// compiler for the specified target and backend. fn codegen_backend_stamp(builder: &Builder, compiler: Compiler, target: Interned, backend: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target) - .join(format!(".librustc_trans-{}.stamp", backend)) + builder.cargo_out(compiler, Mode::Codegen, target) + .join(format!(".librustc_codegen_llvm-{}.stamp", backend)) } pub fn compiler_file(builder: &Builder, @@ -971,8 +971,8 @@ impl Step for Assemble { } // Link the compiler binary itself into place - let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host); - let rustc = out_dir.join(exe("rustc", &*host)); + let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); + let rustc = out_dir.join(exe("rustc_binary", &*host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); let compiler = builder.rustc(target_compiler); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6dd6291be2..11e0b6900b 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -82,6 +82,7 @@ pub struct Config { pub llvm_version_check: bool, pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, + pub llvm_clang_cl: Option, pub llvm_targets: Option, pub llvm_experimental_targets: String, pub llvm_link_jobs: Option, @@ -124,7 +125,7 @@ pub struct Config { // misc pub low_priority: bool, pub channel: String, - pub quiet_tests: bool, + pub verbose_tests: bool, pub test_miri: bool, pub save_toolstates: Option, pub print_step_timings: bool, @@ -250,6 +251,7 @@ struct Llvm { experimental_targets: Option, link_jobs: Option, link_shared: Option, + clang_cl: Option } #[derive(Deserialize, Default, Clone)] @@ -299,8 +301,9 @@ struct Rust { ignore_git: Option, debug: Option, dist_src: Option, - quiet_tests: Option, + verbose_tests: Option, test_miri: Option, + incremental: Option, save_toolstates: Option, codegen_backends: Option>, codegen_backends_dir: Option, @@ -504,6 +507,7 @@ impl Config { config.llvm_experimental_targets = llvm.experimental_targets.clone() .unwrap_or("WebAssembly".to_string()); config.llvm_link_jobs = llvm.link_jobs; + config.llvm_clang_cl = llvm.clang_cl.clone(); } if let Some(ref rust) = toml.rust { @@ -524,8 +528,12 @@ impl Config { set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); set(&mut config.rust_dist_src, rust.dist_src); - set(&mut config.quiet_tests, rust.quiet_tests); + set(&mut config.verbose_tests, rust.verbose_tests); set(&mut config.test_miri, rust.test_miri); + // in the case "false" is set explicitly, do not overwrite the command line args + if let Some(true) = rust.incremental { + config.incremental = true; + } set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 3574b7d210..446db9c0a9 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -47,7 +47,7 @@ o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") o("experimental-parallel-queries", "rust.experimental-parallel-queries", "build rustc with experimental parallelization") o("test-miri", "rust.test-miri", "run miri's test suite") o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata") -o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests") +o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests") o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds") o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds") o("local-rust", None, "use an installed rustc rather than downloading a snapshot") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e21a59390b..7341137e20 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -722,7 +722,7 @@ impl Step for Analysis { let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); - let src = builder.stage_out(compiler, Mode::Libstd) + let src = builder.stage_out(compiler, Mode::Std) .join(target).join(builder.cargo_dir()).join("deps"); let image_src = src.join("save-analysis"); @@ -951,13 +951,16 @@ impl Step for PlainSourceTarball { has_cargo_vendor |= line.starts_with("cargo-vendor "); } if !has_cargo_vendor { - let mut cmd = Command::new(&builder.initial_cargo); - cmd.arg("install") - .arg("--force") + let mut cmd = builder.cargo( + builder.compiler(0, builder.config.build), + Mode::ToolRustc, + builder.config.build, + "install" + ); + cmd.arg("--force") .arg("--debug") .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &builder.initial_rustc); + .arg("cargo-vendor"); if let Some(dir) = builder.openssl_install_dir(builder.config.build) { builder.ensure(native::Openssl { target: builder.config.build, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 16f4b29dcc..19599b33eb 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -28,7 +28,7 @@ use build_helper::up_to_date; use util::symlink_dir; use builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; -use tool::Tool; +use tool::{self, prepare_tool_cargo, Tool}; use compile; use cache::{INTERNER, Interned}; use config::Config; @@ -70,7 +70,7 @@ macro_rules! book { book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; - Rustdoc, "src/doc/rustdoc", "rustdoc"; + RustdocBook, "src/doc/rustdoc", "rustdoc"; RustcBook, "src/doc/rustc", "rustc"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; ); @@ -272,6 +272,12 @@ impl Step for TheBook { name: INTERNER.intern_string(format!("{}/second-edition", name)), }); + // build book 2018 edition + builder.ensure(Rustbook { + target, + name: INTERNER.intern_string(format!("{}/2018-edition", name)), + }); + // build the version info page and CSS builder.ensure(Standalone { compiler, @@ -457,7 +463,7 @@ impl Step for Std { }; builder.ensure(compile::Std { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Libstd) + let out_dir = builder.stage_out(compiler, Mode::Std) .join(target).join("doc"); // Here what we're doing is creating a *symlink* (directory junction on @@ -477,7 +483,7 @@ impl Step for Std { builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, "doc"); compile::std_cargo(builder, &compiler, target, &mut cargo); // Keep a whitelist so we do not build internal stdlib crates, these will be @@ -540,7 +546,7 @@ impl Step for Test { builder.ensure(Std { stage, target }); builder.ensure(compile::Test { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Libtest) + let out_dir = builder.stage_out(compiler, Mode::Test) .join(target).join("doc"); // See docs in std above for why we symlink @@ -548,7 +554,7 @@ impl Step for Test { builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc"); compile::test_cargo(builder, &compiler, target, &mut cargo); cargo.arg("--no-deps").arg("-p").arg("test"); @@ -608,7 +614,7 @@ impl Step for WhitelistedRustc { builder.ensure(Std { stage, target }); builder.ensure(compile::Rustc { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Librustc) + let out_dir = builder.stage_out(compiler, Mode::Rustc) .join(target).join("doc"); // See docs in std above for why we symlink @@ -616,7 +622,7 @@ impl Step for WhitelistedRustc { builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); compile::rustc_cargo(builder, &mut cargo); // We don't want to build docs for internal compiler dependencies in this @@ -665,8 +671,12 @@ impl Step for Rustc { let stage = self.stage; let target = self.target; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + + // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); + + // Get the correct compiler for this stage. let compiler = builder.compiler(stage, builder.config.build); let rustdoc = builder.rustdoc(compiler.host); let compiler = if builder.force_use_stage1(compiler, target) { @@ -676,22 +686,24 @@ impl Step for Rustc { }; if !builder.config.compiler_docs { - builder.info(&format!("\tskipping - compiler docs disabled")); + builder.info(&format!("\tskipping - compiler/librustdoc docs disabled")); return; } - // Build libstd docs so that we generate relative links + // Build libstd docs so that we generate relative links. builder.ensure(Std { stage, target }); + // Build rustc. builder.ensure(compile::Rustc { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Librustc) - .join(target).join("doc"); + // We do not symlink to the same shared folder that already contains std library // documentation from previous steps as we do not want to include that. + let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc"); builder.clear_if_dirty(&out, &rustdoc); t!(symlink_dir_force(&builder.config, &out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); + // Build cargo command. + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); cargo.env("RUSTDOCFLAGS", "--document-private-items"); compile::rustc_cargo(builder, &mut cargo); @@ -729,6 +741,78 @@ fn find_compiler_crates( } } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Rustdoc { + stage: u32, + target: Interned, +} + +impl Step for Rustdoc { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.krate("rustdoc-tool") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Rustdoc { + stage: run.builder.top_stage, + target: run.target, + }); + } + + /// Generate compiler documentation. + /// + /// This will generate all documentation for compiler and dependencies. + /// Compiler documentation is distributed separately, so we make sure + /// we do not merge it with the other documentation from std, test and + /// proc_macros. This is largely just a wrapper around `cargo doc`. + fn run(self, builder: &Builder) { + let stage = self.stage; + let target = self.target; + builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target)); + + // This is the intended out directory for compiler documentation. + let out = builder.compiler_doc_out(target); + t!(fs::create_dir_all(&out)); + + // Get the correct compiler for this stage. + let compiler = builder.compiler(stage, builder.config.build); + let rustdoc = builder.rustdoc(compiler.host); + let compiler = if builder.force_use_stage1(compiler, target) { + builder.compiler(1, compiler.host) + } else { + compiler + }; + + if !builder.config.compiler_docs { + builder.info(&format!("\tskipping - compiler/librustdoc docs disabled")); + return; + } + + // Build libstd docs so that we generate relative links. + builder.ensure(Std { stage, target }); + + // Build rustdoc. + builder.ensure(tool::Rustdoc { host: compiler.host }); + + // Symlink compiler docs to the output directory of rustdoc documentation. + let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc"); + t!(fs::create_dir_all(&out_dir)); + builder.clear_if_dirty(&out, &rustdoc); + t!(symlink_dir_force(&builder.config, &out, &out_dir)); + + // Build cargo command. + let mut cargo = prepare_tool_cargo( + builder, compiler, Mode::ToolRustc, target, "doc", "src/tools/rustdoc"); + + cargo.env("RUSTDOCFLAGS", "--document-private-items"); + builder.run(&mut cargo); + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { target: Interned, diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 5315a3028f..e5dceccdf8 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -19,10 +19,10 @@ use std::process; use getopts::Options; -use {Build, DocTests}; +use builder::Builder; use config::Config; use metadata; -use builder::Builder; +use {Build, DocTests}; use cache::{Interned, INTERNER}; @@ -59,6 +59,9 @@ pub enum Subcommand { }, Test { paths: Vec, + /// Whether to automatically update stderr/stdout files + bless: bool, + compare_mode: Option, test_args: Vec, rustc_args: Vec, fail_fast: bool, @@ -90,7 +93,8 @@ impl Default for Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { let mut extra_help = String::new(); - let mut subcommand_help = format!("\ + let mut subcommand_help = format!( + "\ Usage: x.py [options] [...] Subcommands: @@ -103,7 +107,8 @@ Subcommands: dist Build distribution artifacts install Install distribution artifacts -To learn more about a subcommand, run `./x.py -h`"); +To learn more about a subcommand, run `./x.py -h`" + ); let mut opts = Options::new(); // Options common to all subcommands @@ -121,33 +126,39 @@ To learn more about a subcommand, run `./x.py -h`"); 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("h", "help", "print this help message"); - opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default", - "VALUE"); + opts.optopt( + "", + "warnings", + "if value is deny, will deny warnings, otherwise use default", + "VALUE", + ); opts.optopt("", "error-format", "rustc error format", "FORMAT"); // fn usage() - let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { - println!("{}", opts.usage(subcommand_help)); - if !extra_help.is_empty() { - println!("{}", extra_help); - } - process::exit(exit_code); - }; + let usage = + |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on // the subcommand. Therefore we must manually identify the subcommand first, so that we can // complete the definition of the options. Then we can use the getopt::Matches object from // there on out. - let subcommand = args.iter().find(|&s| + let subcommand = args.iter().find(|&s| { (s == "build") - || (s == "check") - || (s == "test") - || (s == "bench") - || (s == "doc") - || (s == "clean") - || (s == "dist") - || (s == "install")); + || (s == "check") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist") + || (s == "install") + }); let subcommand = match subcommand { Some(s) => s, None => { @@ -162,7 +173,7 @@ To learn more about a subcommand, run `./x.py -h`"); // Some subcommands get extra options match subcommand.as_str() { - "test" => { + "test" => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); opts.optmulti("", "test-args", "extra arguments", "ARGS"); opts.optmulti( @@ -173,10 +184,25 @@ To learn more about a subcommand, run `./x.py -h`"); ); opts.optflag("", "no-doc", "do not run doc tests"); opts.optflag("", "doc", "only run doc tests"); - }, - "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, - "clean" => { opts.optflag("", "all", "clean all build artifacts"); }, - _ => { }, + opts.optflag( + "", + "bless", + "update all stderr/stdout files of failing ui tests", + ); + opts.optopt( + "", + "compare-mode", + "mode describing what file the actual ui output will be compared to", + "COMPARE MODE", + ); + } + "bench" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + } + "clean" => { + opts.optflag("", "all", "clean all build artifacts"); + } + _ => {} }; // Done specifying what options are possible, so do the getopts parsing @@ -196,21 +222,24 @@ To learn more about a subcommand, run `./x.py -h`"); if check_subcommand != subcommand { pass_sanity_check = false; } - }, + } None => { pass_sanity_check = false; } } if !pass_sanity_check { println!("{}\n", subcommand_help); - println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ - You may need to move some options to after the subcommand.\n"); + println!( + "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n" + ); process::exit(1); } // Extra help text for some commands match subcommand.as_str() { "build" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: @@ -232,10 +261,12 @@ Arguments: This will first build everything once (like --stage 0 without further arguments would), and then use the compiler built in stage 0 to build src/libtest and its dependencies. - Once this is done, build/$ARCH/stage1 contains a usable compiler."); + Once this is done, build/$ARCH/stage1 contains a usable compiler.", + ); } "check" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: @@ -247,10 +278,12 @@ Arguments: also that since we use `cargo check`, by default this will automatically enable incremental compilation, so there's no need to pass it separately, though it won't hurt. We also completely ignore the stage passed, as there's no way to compile in non-stage 0 without actually building - the compiler."); + the compiler.", + ); } "test" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories to tests that should be compiled and run. For example: @@ -258,15 +291,19 @@ Arguments: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map ./x.py test src/libstd --stage 0 + ./x.py test src/test/ui --bless + ./x.py test src/test/ui --compare-mode nll If no arguments are passed then the complete artifacts for that stage are compiled and tested. ./x.py test - ./x.py test --stage 1"); + ./x.py test --stage 1", + ); } "doc" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories of documentation to build. For example: @@ -278,12 +315,16 @@ Arguments: If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1"); + ./x.py doc --stage 1", + ); } - _ => { } + _ => {} }; // Get any optional paths which occur after the subcommand - let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); + let paths = matches.free[1..] + .iter() + .map(|p| p.into()) + .collect::>(); let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -302,9 +343,12 @@ Arguments: let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); } else if subcommand.as_str() != "clean" { - extra_help.push_str(format!( - "Run `./x.py {} -h -v` to see a list of available paths.", - subcommand).as_str()); + extra_help.push_str( + format!( + "Run `./x.py {} -h -v` to see a list of available paths.", + subcommand + ).as_str(), + ); } // User passed in -h/--help? @@ -313,36 +357,28 @@ Arguments: } let cmd = match subcommand.as_str() { - "build" => { - Subcommand::Build { paths: paths } - } - "check" => { - Subcommand::Check { paths: paths } - } - "test" => { - Subcommand::Test { - paths, - test_args: matches.opt_strs("test-args"), - rustc_args: matches.opt_strs("rustc-args"), - fail_fast: !matches.opt_present("no-fail-fast"), - doc_tests: if matches.opt_present("doc") { - DocTests::Only - } else if matches.opt_present("no-doc") { - DocTests::No - } else { - DocTests::Yes - } - } - } - "bench" => { - Subcommand::Bench { - paths, - test_args: matches.opt_strs("test-args"), - } - } - "doc" => { - Subcommand::Doc { paths: paths } - } + "build" => Subcommand::Build { paths: paths }, + "check" => Subcommand::Check { paths: paths }, + "test" => Subcommand::Test { + paths, + bless: matches.opt_present("bless"), + compare_mode: matches.opt_str("compare-mode"), + test_args: matches.opt_strs("test-args"), + rustc_args: matches.opt_strs("rustc-args"), + fail_fast: !matches.opt_present("no-fail-fast"), + doc_tests: if matches.opt_present("doc") { + DocTests::Only + } else if matches.opt_present("no-doc") { + DocTests::No + } else { + DocTests::Yes + }, + }, + "bench" => Subcommand::Bench { + paths, + test_args: matches.opt_strs("test-args"), + }, + "doc" => Subcommand::Doc { paths: paths }, "clean" => { if paths.len() > 0 { println!("\nclean does not take a path argument\n"); @@ -353,22 +389,13 @@ Arguments: all: matches.opt_present("all"), } } - "dist" => { - Subcommand::Dist { - paths, - } - } - "install" => { - Subcommand::Install { - paths, - } - } + "dist" => Subcommand::Dist { paths }, + "install" => Subcommand::Install { paths }, _ => { usage(1, &opts, &subcommand_help, &extra_help); } }; - Flags { verbose: matches.opt_count("verbose"), stage: matches.opt_str("stage").map(|j| j.parse().unwrap()), @@ -377,15 +404,21 @@ Arguments: rustc_error_format: matches.opt_str("error-format"), keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), host: split(matches.opt_strs("host")) - .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), + .into_iter() + .map(|x| INTERNER.intern_string(x)) + .collect::>(), target: split(matches.opt_strs("target")) - .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), + .into_iter() + .map(|x| INTERNER.intern_string(x)) + .collect::>(), config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd, incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) - .into_iter().map(|p| p.into()).collect::>(), + .into_iter() + .map(|p| p.into()) + .collect::>(), warnings: matches.opt_str("warnings").map(|v| v == "deny"), } } @@ -394,9 +427,11 @@ Arguments: impl Subcommand { pub fn test_args(&self) -> Vec<&str> { match *self { - Subcommand::Test { ref test_args, .. } | - Subcommand::Bench { ref test_args, .. } => { - test_args.iter().flat_map(|s| s.split_whitespace()).collect() + Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { + test_args + .iter() + .flat_map(|s| s.split_whitespace()) + .collect() } _ => Vec::new(), } @@ -404,9 +439,10 @@ impl Subcommand { pub fn rustc_args(&self) -> Vec<&str> { match *self { - Subcommand::Test { ref rustc_args, .. } => { - rustc_args.iter().flat_map(|s| s.split_whitespace()).collect() - } + Subcommand::Test { ref rustc_args, .. } => rustc_args + .iter() + .flat_map(|s| s.split_whitespace()) + .collect(), _ => Vec::new(), } } @@ -424,8 +460,27 @@ impl Subcommand { _ => DocTests::Yes, } } + + pub fn bless(&self) -> bool { + match *self { + Subcommand::Test { bless, .. } => bless, + _ => false, + } + } + + pub fn compare_mode(&self) -> Option<&str> { + match *self { + Subcommand::Test { + ref compare_mode, .. + } => compare_mode.as_ref().map(|s| &s[..]), + _ => None, + } + } } fn split(s: Vec) -> Vec { - s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect() + s.iter() + .flat_map(|s| s.split(',')) + .map(|s| s.to_string()) + .collect() } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e53fef0678..6e77413f06 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -280,7 +280,8 @@ pub struct Build { struct Crate { name: Interned, version: String, - deps: Vec>, + deps: HashSet>, + id: String, path: PathBuf, doc_step: String, build_step: String, @@ -307,16 +308,30 @@ impl Crate { #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. - Libstd, + Std, /// Build libtest, placing output in the "stageN-test" directory. - Libtest, + Test, - /// Build librustc and compiler libraries, placing output in the "stageN-rustc" directory. - Librustc, + /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. + Rustc, - /// Build some tool, placing output in the "stageN-tools" directory. - Tool, + /// Build codegen libraries, placing output in the "stageN-codegen" directory + Codegen, + + /// Build some tools, placing output in the "stageN-tools" directory. + ToolStd, + ToolTest, + ToolRustc, +} + +impl Mode { + pub fn is_tool(&self) -> bool { + match self { + Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => true, + _ => false + } + } } impl Build { @@ -517,10 +532,11 @@ impl Build { /// The mode indicates what the root directory is for. fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf { let suffix = match mode { - Mode::Libstd => "-std", - Mode::Libtest => "-test", - Mode::Tool => "-tools", - Mode::Librustc => "-rustc", + Mode::Std => "-std", + Mode::Test => "-test", + Mode::Codegen => "-rustc", + Mode::Rustc => "-rustc", + Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => "-tools", }; self.out.join(&*compiler.host) .join(format!("stage{}{}", compiler.stage, suffix)) @@ -592,12 +608,20 @@ impl Build { Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target)) } else { let base = self.llvm_out(self.config.build).join("build"); - let exe = exe("FileCheck", &*target); - if !self.config.ninja && self.config.build.contains("msvc") { - base.join("Release/bin").join(exe) + let base = if !self.config.ninja && self.config.build.contains("msvc") { + if self.config.llvm_optimize { + if self.config.llvm_release_debuginfo { + base.join("RelWithDebInfo") + } else { + base.join("Release") + } + } else { + base.join("Debug") + } } else { - base.join("bin").join(exe) - } + base + }; + base.join("bin").join(exe("FileCheck", &*target)) } } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 5f1df1d26e..718a6da363 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -11,6 +11,7 @@ use std::collections::HashMap; use std::process::Command; use std::path::PathBuf; +use std::collections::HashSet; use build_helper::output; use serde_json; @@ -45,45 +46,17 @@ struct ResolveNode { } pub fn build(build: &mut Build) { - build_krate(build, "src/libstd"); - build_krate(build, "src/libtest"); - build_krate(build, "src/rustc"); -} + let mut resolves = Vec::new(); + build_krate(&build.std_features(), build, &mut resolves, "src/libstd"); + build_krate("", build, &mut resolves, "src/libtest"); + build_krate(&build.rustc_features(), build, &mut resolves, "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.initial_cargo); - cargo.arg("metadata") - .arg("--format-version").arg("1") - .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); - let output = output(&mut cargo); - let output: Output = serde_json::from_str(&output).unwrap(); let mut id2name = HashMap::new(); - for package in output.packages { - if package.source.is_none() { - let name = INTERNER.intern_string(package.name); - id2name.insert(package.id, name); - let mut path = PathBuf::from(package.manifest_path); - path.pop(); - build.crates.insert(name, Crate { - build_step: format!("build-crate-{}", name), - doc_step: format!("doc-crate-{}", name), - test_step: format!("test-crate-{}", name), - bench_step: format!("bench-crate-{}", name), - name, - version: package.version, - deps: Vec::new(), - path, - }); - } + for (name, krate) in build.crates.iter() { + id2name.insert(krate.id.clone(), name.clone()); } - for node in output.resolve.nodes { + for node in resolves { let name = match id2name.get(&node.id) { Some(name) => name, None => continue, @@ -95,7 +68,42 @@ fn build_krate(build: &mut Build, krate: &str) { Some(dep) => dep, None => continue, }; - krate.deps.push(*dep); + krate.deps.insert(*dep); } } } + +fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec, 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.initial_cargo); + cargo.arg("metadata") + .arg("--format-version").arg("1") + .arg("--features").arg(features) + .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); + let output = output(&mut cargo); + let output: Output = serde_json::from_str(&output).unwrap(); + for package in output.packages { + if package.source.is_none() { + let name = INTERNER.intern_string(package.name); + let mut path = PathBuf::from(package.manifest_path); + path.pop(); + build.crates.insert(name, Crate { + build_step: format!("build-crate-{}", name), + doc_step: format!("doc-crate-{}", name), + test_step: format!("test-crate-{}", name), + bench_step: format!("bench-crate-{}", name), + name, + version: package.version, + id: package.id, + deps: HashSet::new(), + path, + }); + } + } + resolves.extend(output.resolve.nodes); +} diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index d952cb5bfc..93292c658b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -275,21 +275,53 @@ fn configure_cmake(builder: &Builder, return } - let cc = builder.cc(target); - let cxx = builder.cxx(target).unwrap(); + let (cc, cxx) = match builder.config.llvm_clang_cl { + Some(ref cl) => (cl.as_ref(), cl.as_ref()), + None => (builder.cc(target), builder.cxx(target).unwrap()), + }; // Handle msvc + ninja + ccache specially (this is what the bots use) if target.contains("msvc") && builder.config.ninja && - builder.config.ccache.is_some() { - let mut cc = env::current_exe().expect("failed to get cwd"); - cc.set_file_name("sccache-plus-cl.exe"); + builder.config.ccache.is_some() + { + let mut wrap_cc = env::current_exe().expect("failed to get cwd"); + wrap_cc.set_file_name("sccache-plus-cl.exe"); - cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) - .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc)); + cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc)); cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap()) - .env("SCCACHE_TARGET", target); + .env("SCCACHE_TARGET", target) + .env("SCCACHE_CC", &cc) + .env("SCCACHE_CXX", &cxx); + + // Building LLVM on MSVC can be a little ludicrous at times. We're so far + // off the beaten path here that I'm not really sure this is even half + // supported any more. Here we're trying to: + // + // * Build LLVM on MSVC + // * Build LLVM with `clang-cl` instead of `cl.exe` + // * Build a project with `sccache` + // * Build for 32-bit as well + // * Build with Ninja + // + // For `cl.exe` there are different binaries to compile 32/64 bit which + // we use but for `clang-cl` there's only one which internally + // multiplexes via flags. As a result it appears that CMake's detection + // of a compiler's architecture and such on MSVC **doesn't** pass any + // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we + // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which + // definitely causes problems since all the env vars are pointing to + // 32-bit libraries. + // + // To hack aroudn this... again... we pass an argument that's + // unconditionally passed in the sccache shim. This'll get CMake to + // correctly diagnose it's doing a 32-bit compilation and LLVM will + // internally configure itself appropriately. + if builder.config.llvm_clang_cl.is_some() && target.contains("i686") { + cfg.env("SCCACHE_EXTRA_ARGS", "-m32"); + } // If ccache is configured we inform the build a little differently hwo // to invoke ccache while also invoking our compilers. @@ -368,9 +400,27 @@ impl Step for Lld { let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld")); configure_cmake(builder, target, &mut cfg, true); + // This is an awful, awful hack. Discovered when we migrated to using + // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of + // tree, will execute `llvm-config --cmakedir` and then tell CMake about + // that directory for later processing. Unfortunately if this path has + // forward slashes in it (which it basically always does on Windows) + // then CMake will hit a syntax error later on as... something isn't + // escaped it seems? + // + // Instead of attempting to fix this problem in upstream CMake and/or + // LLVM/LLD we just hack around it here. This thin wrapper will take the + // output from llvm-config and replace all instances of `\` with `/` to + // ensure we don't hit the same bugs with escaping. It means that you + // can't build on a system where your paths require `\` on Windows, but + // there's probably a lot of reasons you can't do that other than this. + let llvm_config_shim = env::current_exe() + .unwrap() + .with_file_name("llvm-config-wrapper"); cfg.out_dir(&out_dir) .profile("Release") - .define("LLVM_CONFIG_PATH", llvm_config) + .env("LLVM_CONFIG_REAL", llvm_config) + .define("LLVM_CONFIG_PATH", llvm_config_shim) .define("LLVM_INCLUDE_TESTS", "OFF"); cfg.build(); @@ -546,8 +596,10 @@ impl Step for Openssl { "arm-linux-androideabi" => "android", "arm-unknown-linux-gnueabi" => "linux-armv4", "arm-unknown-linux-gnueabihf" => "linux-armv4", + "armv6-unknown-netbsd-eabihf" => "BSD-generic32", "armv7-linux-androideabi" => "android-armv7", "armv7-unknown-linux-gnueabihf" => "linux-armv4", + "armv7-unknown-netbsd-eabihf" => "BSD-generic32", "i586-unknown-linux-gnu" => "linux-elf", "i586-unknown-linux-musl" => "linux-elf", "i686-apple-darwin" => "darwin-i386-cc", diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 650e09feb0..d2fd798723 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -15,25 +15,26 @@ use std::env; use std::ffi::OsString; -use std::iter; use std::fmt; use std::fs::{self, File}; -use std::path::{PathBuf, Path}; -use std::process::Command; use std::io::Read; +use std::iter; +use std::path::{Path, PathBuf}; +use std::process::Command; use build_helper::{self, output}; -use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step}; -use Crate as CargoCrate; -use cache::{INTERNER, Interned}; +use builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; +use cache::{Interned, INTERNER}; use compile; use dist; +use flags::Subcommand; use native; use tool::{self, Tool}; -use util::{self, dylib_path, dylib_path_var}; -use {Mode, DocTests}; use toolstate::ToolState; +use util::{self, dylib_path, dylib_path_var}; +use Crate as CargoCrate; +use {DocTests, Mode}; const ADB_TEST_DIR: &str = "/data/tmp/work"; @@ -46,6 +47,16 @@ pub enum TestKind { Bench, } +impl From for TestKind { + fn from(kind: Kind) -> Self { + match kind { + Kind::Test => TestKind::Test, + Kind::Bench => TestKind::Bench, + _ => panic!("unexpected kind in crate: {:?}", kind), + } + } +} + impl TestKind { // Return the cargo subcommand for this test kind fn subcommand(self) -> &'static str { @@ -113,13 +124,18 @@ impl Step for Linkcheck { builder.default_doc(None); let _time = util::timeit(&builder); - try_run(builder, builder.tool_cmd(Tool::Linkchecker) - .arg(builder.out.join(host).join("doc"))); + try_run( + builder, + builder + .tool_cmd(Tool::Linkchecker) + .arg(builder.out.join(host).join("doc")), + ); } fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/linkchecker").default_condition(builder.config.docs) + run.path("src/tools/linkchecker") + .default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -154,7 +170,10 @@ impl Step for Cargotest { /// test` to ensure that we don't regress the test suites there. fn run(self, builder: &Builder) { let compiler = builder.compiler(self.stage, self.host); - builder.ensure(compile::Rustc { compiler, target: compiler.host }); + builder.ensure(compile::Rustc { + compiler, + target: compiler.host, + }); // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise @@ -164,10 +183,13 @@ impl Step for Cargotest { let _time = util::timeit(&builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); - try_run(builder, cmd.arg(&builder.initial_cargo) - .arg(&out_dir) - .env("RUSTC", builder.rustc(compiler)) - .env("RUSTDOC", builder.rustdoc(compiler.host))); + try_run( + builder, + cmd.arg(&builder.initial_cargo) + .arg(&out_dir) + .env("RUSTC", builder.rustc(compiler)) + .env("RUSTDOC", builder.rustdoc(compiler.host)), + ); } } @@ -196,9 +218,14 @@ impl Step for Cargo { fn run(self, builder: &Builder) { let compiler = builder.compiler(self.stage, self.host); - builder.ensure(tool::Cargo { compiler, target: self.host }); - let mut cargo = builder.cargo(compiler, Mode::Tool, self.host, "test"); - cargo.arg("--manifest-path").arg(builder.src.join("src/tools/cargo/Cargo.toml")); + builder.ensure(tool::Cargo { + compiler, + target: self.host, + }); + let mut cargo = builder.cargo(compiler, Mode::ToolRustc, self.host, "test"); + cargo + .arg("--manifest-path") + .arg(builder.src.join("src/tools/cargo/Cargo.toml")); if !builder.fail_fast { cargo.arg("--no-fail-fast"); } @@ -210,7 +237,10 @@ impl Step for Cargo { // available. cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); - try_run(builder, cargo.env("PATH", &path_for_cargo(builder, compiler))); + try_run( + builder, + cargo.env("PATH", &path_for_cargo(builder, compiler)), + ); } } @@ -253,6 +283,7 @@ impl Step for Rls { let mut cargo = tool::prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, host, "test", "src/tools/rls"); @@ -307,6 +338,7 @@ impl Step for Rustfmt { let mut cargo = tool::prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, host, "test", "src/tools/rustfmt"); @@ -360,8 +392,10 @@ impl Step for Miri { extra_features: Vec::new(), }); if let Some(miri) = miri { - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(builder.src.join("src/tools/miri/Cargo.toml")); + let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "test"); + cargo + .arg("--manifest-path") + .arg(builder.src.join("src/tools/miri/Cargo.toml")); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -416,8 +450,10 @@ impl Step for Clippy { extra_features: Vec::new(), }); if let Some(clippy) = clippy { - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(builder.src.join("src/tools/clippy/Cargo.toml")); + let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "test"); + cargo + .arg("--manifest-path") + .arg(builder.src.join("src/tools/clippy/Cargo.toml")); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -425,7 +461,9 @@ impl Step for Clippy { cargo.env("SYSROOT", builder.sysroot(compiler)); cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); - let host_libs = builder.stage_out(compiler, Mode::Tool).join(builder.cargo_dir()); + let host_libs = builder + .stage_out(compiler, Mode::ToolRustc) + .join(builder.cargo_dir()); cargo.env("HOST_LIBS", host_libs); // clippy tests need to find the driver cargo.env("CLIPPY_DRIVER_PATH", clippy); @@ -467,23 +505,30 @@ impl Step for RustdocTheme { fn make_run(run: RunConfig) { let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocTheme { - compiler: compiler, - }); + run.builder.ensure(RustdocTheme { compiler: compiler }); } fn run(self, builder: &Builder) { let rustdoc = builder.out.join("bootstrap/debug/rustdoc"); let mut cmd = builder.tool_cmd(Tool::RustdocTheme); cmd.arg(rustdoc.to_str().unwrap()) - .arg(builder.src.join("src/librustdoc/html/static/themes").to_str().unwrap()) - .env("RUSTC_STAGE", self.compiler.stage.to_string()) - .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) - .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host)) - .env("CFG_RELEASE_CHANNEL", &builder.config.channel) - .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) - .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) - .env("RUSTC_BOOTSTRAP", "1"); + .arg( + builder + .src + .join("src/librustdoc/html/static/themes") + .to_str() + .unwrap(), + ) + .env("RUSTC_STAGE", self.compiler.stage.to_string()) + .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) + .env( + "RUSTDOC_LIBDIR", + builder.sysroot_libdir(self.compiler, self.compiler.host), + ) + .env("CFG_RELEASE_CHANNEL", &builder.config.channel) + .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) + .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) + .env("RUSTC_BOOTSTRAP", "1"); if let Some(linker) = builder.linker(self.compiler.host) { cmd.env("RUSTC_TARGET_LINKER", linker); } @@ -523,7 +568,9 @@ impl Step for RustdocJS { }); builder.run(&mut command); } else { - builder.info(&format!("No nodejs found, skipping \"src/test/rustdoc-js\" tests")); + builder.info(&format!( + "No nodejs found, skipping \"src/test/rustdoc-js\" tests" + )); } } } @@ -559,6 +606,7 @@ impl Step for RustdocUi { target: self.target, mode: "ui", suite: "rustdoc-ui", + path: None, compare_mode: None, }) } @@ -584,7 +632,7 @@ impl Step for Tidy { if !builder.config.vendor { cmd.arg("--no-vendor"); } - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cmd.arg("--quiet"); } @@ -663,7 +711,7 @@ macro_rules! test_definitions { const ONLY_HOSTS: bool = $host; fn should_run(run: ShouldRun) -> ShouldRun { - run.path($path) + run.suite_path($path) } fn make_run(run: RunConfig) { @@ -681,6 +729,7 @@ macro_rules! test_definitions { target: self.target, mode: $mode, suite: $suite, + path: Some($path), compare_mode: $compare_mode, }) } @@ -835,7 +884,7 @@ test!(RunFailFullDepsPretty { host: true }); -host_test!(RunMake { +default_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" @@ -853,6 +902,7 @@ struct Compiletest { target: Interned, mode: &'static str, suite: &'static str, + path: Option<&'static str>, compare_mode: Option<&'static str>, } @@ -873,7 +923,9 @@ impl Step for Compiletest { let target = self.target; let mode = self.mode; let suite = self.suite; - let compare_mode = self.compare_mode; + + // Path for test suite + let suite_path = self.path.unwrap_or(""); // Skip codegen tests if they aren't enabled in configuration. if !builder.config.codegen_tests && suite == "codegen" { @@ -902,15 +954,15 @@ impl Step for Compiletest { builder.ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), - host: target + host: target, }); } if suite.ends_with("fulldeps") || // FIXME: Does pretty need librustc compiled? Note that there are // fulldeps test suites with mode = pretty as well. - mode == "pretty" || - mode == "rustdoc" { + mode == "pretty" + { builder.ensure(compile::Rustc { compiler, target }); } @@ -923,26 +975,40 @@ impl Step for Compiletest { // compiletest currently has... a lot of arguments, so let's just pass all // of them! - cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler)); - cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target)); + cmd.arg("--compile-lib-path") + .arg(builder.rustc_libdir(compiler)); + cmd.arg("--run-lib-path") + .arg(builder.sysroot_libdir(compiler, target)); cmd.arg("--rustc-path").arg(builder.rustc(compiler)); let is_rustdoc_ui = suite.ends_with("rustdoc-ui"); // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" || - (mode == "run-make" && suite.ends_with("fulldeps")) || - (mode == "ui" && is_rustdoc_ui) { - cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); + if mode == "rustdoc" + || (mode == "run-make" && suite.ends_with("fulldeps")) + || (mode == "ui" && is_rustdoc_ui) + { + cmd.arg("--rustdoc-path") + .arg(builder.rustdoc(compiler.host)); } - cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite)); - cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite)); - cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target)); + cmd.arg("--src-base") + .arg(builder.src.join("src/test").join(suite)); + cmd.arg("--build-base") + .arg(testdir(builder, compiler.host).join(suite)); + cmd.arg("--stage-id") + .arg(format!("stage{}-{}", compiler.stage, target)); cmd.arg("--mode").arg(mode); cmd.arg("--target").arg(target); cmd.arg("--host").arg(&*compiler.host); - cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build)); + cmd.arg("--llvm-filecheck") + .arg(builder.llvm_filecheck(builder.config.build)); + + if builder.config.cmd.bless() { + cmd.arg("--bless"); + } + + let compare_mode = builder.config.cmd.compare_mode().or(self.compare_mode); if let Some(ref nodejs) = builder.config.nodejs { cmd.arg("--nodejs").arg(nodejs); @@ -972,8 +1038,10 @@ impl Step for Compiletest { cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags.clone(); - targetflags.push(format!("-Lnative={}", - builder.test_helpers_out(target).display())); + targetflags.push(format!( + "-Lnative={}", + builder.test_helpers_out(target).display() + )); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); @@ -997,13 +1065,28 @@ impl Step for Compiletest { cmd.arg("--lldb-python-dir").arg(dir); } - cmd.args(&builder.config.cmd.test_args()); + // Get paths from cmd args + let paths = match &builder.config.cmd { + Subcommand::Test { ref paths, .. } => &paths[..], + _ => &[], + }; + + // Get test-args by striping suite path + let mut test_args: Vec<&str> = paths + .iter() + .filter(|p| p.starts_with(suite_path) && p.is_file()) + .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap()) + .collect(); + + test_args.append(&mut builder.config.cmd.test_args()); + + cmd.args(&test_args); if builder.is_verbose() { cmd.arg("--verbose"); } - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cmd.arg("--quiet"); } @@ -1022,35 +1105,47 @@ impl Step for Compiletest { // 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 !builder.config.dry_run && mode == "run-make" { + if !builder.config.dry_run && suite == "run-make-fulldeps" { let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); - cmd.arg("--cc").arg(builder.cc(target)) - .arg("--cxx").arg(builder.cxx(target).unwrap()) - .arg("--cflags").arg(builder.cflags(target).join(" ")) - .arg("--llvm-components").arg(llvm_components.trim()) - .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + cmd.arg("--cc") + .arg(builder.cc(target)) + .arg("--cxx") + .arg(builder.cxx(target).unwrap()) + .arg("--cflags") + .arg(builder.cflags(target).join(" ")) + .arg("--llvm-components") + .arg(llvm_components.trim()) + .arg("--llvm-cxxflags") + .arg(llvm_cxxflags.trim()); if let Some(ar) = builder.ar(target) { cmd.arg("--ar").arg(ar); } } } - if mode == "run-make" && !builder.config.llvm_enabled { - builder.info( - &format!("Ignoring run-make test suite as they generally don't work without LLVM")); + if suite == "run-make-fulldeps" && !builder.config.llvm_enabled { + builder.info(&format!( + "Ignoring run-make test suite as they generally don't work without LLVM" + )); return; } - if mode != "run-make" { - cmd.arg("--cc").arg("") - .arg("--cxx").arg("") - .arg("--cflags").arg("") - .arg("--llvm-components").arg("") - .arg("--llvm-cxxflags").arg(""); + if suite != "run-make-fulldeps" { + cmd.arg("--cc") + .arg("") + .arg("--cxx") + .arg("") + .arg("--cflags") + .arg("") + .arg("--llvm-components") + .arg("") + .arg("--llvm-cxxflags") + .arg(""); } if builder.remote_tested(target) { - cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient)); + cmd.arg("--remote-test-client") + .arg(builder.tool_exe(Tool::RemoteTestClient)); } // Running a C compiler on MSVC requires a few env vars to be set, to be @@ -1083,7 +1178,7 @@ impl Step for Compiletest { if target.contains("android") { // Assume that cc for this target comes from the android sysroot cmd.arg("--android-cross-path") - .arg(builder.cc(target).parent().unwrap().parent().unwrap()); + .arg(builder.cc(target).parent().unwrap().parent().unwrap()); } else { cmd.arg("--android-cross-path").arg(""); } @@ -1091,16 +1186,20 @@ impl Step for Compiletest { builder.ci_env.force_coloring_in_ci(&mut cmd); let _folder = builder.fold_output(|| format!("test_{}", suite)); - builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})", - suite, mode, &compiler.host, target)); + builder.info(&format!( + "Check compiletest suite={} mode={} ({} -> {})", + suite, mode, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cmd); if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode)); - builder.info(&format!("Check compiletest suite={} mode={} compare_mode={} ({} -> {})", - suite, mode, compare_mode, &compiler.host, target)); + builder.info(&format!( + "Check compiletest suite={} mode={} compare_mode={} ({} -> {})", + suite, mode, compare_mode, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cmd); } @@ -1131,7 +1230,10 @@ impl Step for DocTest { fn run(self, builder: &Builder) { let compiler = self.compiler; - builder.ensure(compile::Test { compiler, target: compiler.host }); + builder.ensure(compile::Test { + compiler, + target: compiler.host, + }); // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` @@ -1143,7 +1245,7 @@ impl Step for DocTest { while let Some(p) = stack.pop() { if p.is_dir() { stack.extend(t!(p.read_dir()).map(|p| t!(p).path())); - continue + continue; } if p.extension().and_then(|s| s.to_str()) != Some("md") { @@ -1250,7 +1352,10 @@ impl Step for ErrorIndex { fn run(self, builder: &Builder) { let compiler = self.compiler; - builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Std { + compiler, + target: compiler.host, + }); let dir = testdir(builder, compiler.host); t!(fs::create_dir_all(&dir)); @@ -1262,7 +1367,6 @@ impl Step for ErrorIndex { .env("CFG_BUILD", &builder.config.build) .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); - let _folder = builder.fold_output(|| "test_error_index"); builder.info(&format!("Testing error-index stage{}", compiler.stage)); let _time = util::timeit(&builder); @@ -1280,7 +1384,7 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool return true; } } - Err(_) => {}, + Err(_) => {} } builder.info(&format!("doc tests for: {}", markdown.display())); @@ -1293,10 +1397,10 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool let test_args = builder.config.cmd.test_args().join(" "); cmd.arg("--test-args").arg(test_args); - if builder.config.quiet_tests { - try_run_quiet(builder, &mut cmd) - } else { + if builder.config.verbose_tests { try_run(builder, &mut cmd) + } else { + try_run_quiet(builder, &mut cmd) } } @@ -1323,13 +1427,7 @@ impl Step for CrateLibrustc { for krate in builder.in_tree_crates("rustc-main") { if run.path.ends_with(&krate.path) { - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(CrateLibrustc { compiler, @@ -1345,7 +1443,7 @@ impl Step for CrateLibrustc { builder.ensure(Crate { compiler: self.compiler, target: self.target, - mode: Mode::Librustc, + mode: Mode::Rustc, test_kind: self.test_kind, krate: self.krate, }); @@ -1375,13 +1473,7 @@ impl Step for CrateNotDefault { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.host); - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(CrateNotDefault { compiler, @@ -1402,14 +1494,13 @@ impl Step for CrateNotDefault { builder.ensure(Crate { compiler: self.compiler, target: self.target, - mode: Mode::Libstd, + mode: Mode::Std, test_kind: self.test_kind, krate: INTERNER.intern_str(self.krate), }); } } - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Crate { pub compiler: Compiler, @@ -1427,10 +1518,11 @@ impl Step for Crate { let builder = run.builder; run = run.krate("test"); for krate in run.builder.in_tree_crates("std") { - if krate.is_local(&run.builder) && - !krate.name.contains("jemalloc") && - !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) && - krate.name != "dlmalloc" { + if krate.is_local(&run.builder) + && !krate.name.contains("jemalloc") + && !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) + && krate.name != "dlmalloc" + { run = run.path(krate.local_path(&builder).to_str().unwrap()); } } @@ -1442,13 +1534,7 @@ impl Step for Crate { let compiler = builder.compiler(builder.top_stage, run.host); let make = |mode: Mode, krate: &CargoCrate| { - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(Crate { compiler, @@ -1461,12 +1547,12 @@ impl Step for Crate { for krate in builder.in_tree_crates("std") { if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Libstd, krate); + make(Mode::Std, krate); } } for krate in builder.in_tree_crates("test") { if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Libtest, krate); + make(Mode::Test, krate); } } } @@ -1501,13 +1587,13 @@ impl Step for Crate { let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); match mode { - Mode::Libstd => { + Mode::Std => { compile::std_cargo(builder, &compiler, target, &mut cargo); } - Mode::Libtest => { + Mode::Test => { compile::test_cargo(builder, &compiler, target, &mut cargo); } - Mode::Librustc => { + Mode::Rustc => { builder.ensure(compile::Rustc { compiler, target }); compile::rustc_cargo(builder, &mut cargo); } @@ -1546,43 +1632,64 @@ impl Step for Crate { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cargo.arg("--quiet"); } if target.contains("emscripten") { - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - builder.config.nodejs.as_ref().expect("nodejs not configured")); + cargo.env( + format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + builder + .config + .nodejs + .as_ref() + .expect("nodejs not configured"), + ); } else if target.starts_with("wasm32") { // Warn about running tests without the `wasm_syscall` feature enabled. // The javascript shim implements the syscall interface so that test // output can be correctly reported. if !builder.config.wasm_syscall { - builder.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \ - test output may not be visible.")); + builder.info(&format!( + "Libstd was built without `wasm_syscall` feature enabled: \ + test output may not be visible." + )); } // On the wasm32-unknown-unknown target we're using LTO which is // incompatible with `-C prefer-dynamic`, so disable that here cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - let node = builder.config.nodejs.as_ref() + let node = builder + .config + .nodejs + .as_ref() .expect("nodejs not configured"); - let runner = format!("{} {}/src/etc/wasm32-shim.js", - node.display(), - builder.src.display()); + let runner = format!( + "{} {}/src/etc/wasm32-shim.js", + node.display(), + builder.src.display() + ); cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner); } else if builder.remote_tested(target) { - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - format!("{} run", - builder.tool_exe(Tool::RemoteTestClient).display())); + cargo.env( + format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()), + ); } let _folder = builder.fold_output(|| { - format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) + format!( + "{}_stage{}-{}", + test_kind.subcommand(), + compiler.stage, + krate + ) }); - builder.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, - &compiler.host, target)); + builder.info(&format!( + "{} {} stage{} ({} -> {})", + test_kind, krate, compiler.stage, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cargo); } @@ -1606,13 +1713,7 @@ impl Step for CrateRustdoc { fn make_run(run: RunConfig) { let builder = run.builder; - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(CrateRustdoc { host: run.host, @@ -1628,6 +1729,7 @@ impl Step for CrateRustdoc { let mut cargo = tool::prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, target, test_kind.subcommand(), "src/tools/rustdoc"); @@ -1640,15 +1742,16 @@ impl Step for CrateRustdoc { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cargo.arg("--quiet"); } - let _folder = builder.fold_output(|| { - format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) - }); - builder.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, - &compiler.host, target)); + let _folder = builder + .fold_output(|| format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)); + builder.info(&format!( + "{} rustdoc stage{} ({} -> {})", + test_kind, compiler.stage, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cargo); @@ -1656,12 +1759,13 @@ impl Step for CrateRustdoc { } fn envify(s: &str) -> String { - s.chars().map(|c| { - match c { + s.chars() + .map(|c| match c { '-' => '_', c => c, - } - }).flat_map(|c| c.to_uppercase()).collect() + }) + .flat_map(|c| c.to_uppercase()) + .collect() } /// Some test suites are run inside emulators or on remote devices, and most @@ -1690,7 +1794,7 @@ impl Step for RemoteCopyLibs { let compiler = self.compiler; let target = self.target; if !builder.remote_tested(target) { - return + return; } builder.ensure(compile::Test { compiler, target }); @@ -1704,9 +1808,9 @@ impl Step for RemoteCopyLibs { let tool = builder.tool_exe(Tool::RemoteTestClient); let mut cmd = Command::new(&tool); cmd.arg("spawn-emulator") - .arg(target) - .arg(&server) - .arg(builder.out.join("tmp")); + .arg(target) + .arg(&server) + .arg(builder.out.join("tmp")); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } @@ -1717,9 +1821,7 @@ impl Step for RemoteCopyLibs { let f = t!(f); let name = f.file_name().into_string().unwrap(); if util::is_dylib(&name) { - builder.run(Command::new(&tool) - .arg("push") - .arg(f.path())); + builder.run(Command::new(&tool).arg("push").arg(f.path())); } } } @@ -1752,17 +1854,21 @@ impl Step for Distcheck { let mut cmd = Command::new("tar"); cmd.arg("-xzf") - .arg(builder.ensure(dist::PlainSourceTarball)) - .arg("--strip-components=1") - .current_dir(&dir); + .arg(builder.ensure(dist::PlainSourceTarball)) + .arg("--strip-components=1") + .current_dir(&dir); builder.run(&mut cmd); - builder.run(Command::new("./configure") - .args(&builder.config.configure_args) - .arg("--enable-vendor") - .current_dir(&dir)); - builder.run(Command::new(build_helper::make(&builder.config.build)) - .arg("check") - .current_dir(&dir)); + builder.run( + Command::new("./configure") + .args(&builder.config.configure_args) + .arg("--enable-vendor") + .current_dir(&dir), + ); + builder.run( + Command::new(build_helper::make(&builder.config.build)) + .arg("check") + .current_dir(&dir), + ); // Now make sure that rust-src has all of libstd's dependencies builder.info(&format!("Distcheck rust-src")); @@ -1772,17 +1878,19 @@ impl Step for Distcheck { let mut cmd = Command::new("tar"); cmd.arg("-xzf") - .arg(builder.ensure(dist::Src)) - .arg("--strip-components=1") - .current_dir(&dir); + .arg(builder.ensure(dist::Src)) + .arg("--strip-components=1") + .current_dir(&dir); builder.run(&mut cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); - builder.run(Command::new(&builder.initial_cargo) - .arg("generate-lockfile") - .arg("--manifest-path") - .arg(&toml) - .current_dir(&dir)); + builder.run( + Command::new(&builder.initial_cargo) + .arg("generate-lockfile") + .arg("--manifest-path") + .arg(&toml) + .current_dir(&dir), + ); } } @@ -1798,11 +1906,11 @@ impl Step for Bootstrap { fn run(self, builder: &Builder) { let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") - .current_dir(builder.src.join("src/bootstrap")) - .env("RUSTFLAGS", "-Cdebuginfo=2") - .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTC", &builder.initial_rustc); + .current_dir(builder.src.join("src/bootstrap")) + .env("RUSTFLAGS", "-Cdebuginfo=2") + .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) + .env("RUSTC_BOOTSTRAP", "1") + .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { // Use the same rustc flags for testing as for "normal" compilation, // so that Cargo doesn’t recompile the entire dependency graph every time: @@ -1813,6 +1921,9 @@ impl Step for Bootstrap { cmd.arg("--no-fail-fast"); } cmd.arg("--").args(&builder.config.cmd.test_args()); + // rustbuild tests are racy on directory creation so just run them one at a time. + // Since there's not many this shouldn't be a problem. + cmd.arg("--test-threads=1"); try_run(builder, &mut cmd); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 4b6e266f1e..0a428a61d1 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -28,7 +28,7 @@ use toolstate::ToolState; pub struct CleanTools { pub compiler: Compiler, pub target: Interned, - pub mode: Mode, + pub cause: Mode, } impl Step for CleanTools { @@ -41,23 +41,23 @@ impl Step for CleanTools { fn run(self, builder: &Builder) { let compiler = self.compiler; let target = self.target; - let mode = self.mode; + let cause = self.cause; // This is for the original compiler, but if we're forced to use stage 1, then // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since // we copy the libs forward. - let tools_dir = builder.stage_out(compiler, Mode::Tool); + let tools_dir = builder.stage_out(compiler, Mode::ToolRustc); let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler }; - for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] { + for &cur_mode in &[Mode::Std, Mode::Test, Mode::Rustc] { let stamp = match cur_mode { - Mode::Libstd => libstd_stamp(builder, compiler, target), - Mode::Libtest => libtest_stamp(builder, compiler, target), - Mode::Librustc => librustc_stamp(builder, compiler, target), + Mode::Std => libstd_stamp(builder, compiler, target), + Mode::Test => libtest_stamp(builder, compiler, target), + Mode::Rustc => librustc_stamp(builder, compiler, target), _ => panic!(), }; @@ -67,7 +67,7 @@ impl Step for CleanTools { // If we are a rustc tool, and std changed, we also need to clear ourselves out -- our // dependencies depend on std. Therefore, we iterate up until our own mode. - if mode == cur_mode { + if cause == cur_mode { break; } } @@ -104,13 +104,13 @@ impl Step for ToolBuild { let is_ext_tool = self.is_ext_tool; match self.mode { - Mode::Libstd => builder.ensure(compile::Std { compiler, target }), - Mode::Libtest => builder.ensure(compile::Test { compiler, target }), - Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }), - Mode::Tool => panic!("unexpected Mode::Tool for tool build") + Mode::ToolStd => builder.ensure(compile::Std { compiler, target }), + Mode::ToolTest => builder.ensure(compile::Test { compiler, target }), + Mode::ToolRustc => builder.ensure(compile::Rustc { compiler, target }), + _ => panic!("unexpected Mode for tool build") } - let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path); + let mut cargo = prepare_tool_cargo(builder, compiler, self.mode, target, "build", path); cargo.arg("--features").arg(self.extra_features.join(" ")); let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); @@ -202,7 +202,7 @@ impl Step for ToolBuild { return None; } } else { - let cargo_out = builder.cargo_out(compiler, Mode::Tool, target) + let cargo_out = builder.cargo_out(compiler, self.mode, target) .join(exe(tool, &compiler.host)); let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host)); builder.copy(&cargo_out, &bin); @@ -214,11 +214,12 @@ impl Step for ToolBuild { pub fn prepare_tool_cargo( builder: &Builder, compiler: Compiler, + mode: Mode, target: Interned, command: &'static str, path: &'static str, ) -> Command { - let mut cargo = builder.cargo(compiler, Mode::Tool, target, command); + let mut cargo = builder.cargo(compiler, mode, target, command); let dir = builder.src.join(path); cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); @@ -253,7 +254,7 @@ pub fn prepare_tool_cargo( } macro_rules! tool { - ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => { + ($($name:ident, $path:expr, $tool_name:expr, $mode:expr $(,llvm_tools = $llvm:expr)*;)+) => { #[derive(Copy, Clone)] pub enum Tool { $( @@ -261,6 +262,22 @@ macro_rules! tool { )+ } + impl Tool { + pub fn get_mode(&self) -> Mode { + let mode = match self { + $(Tool::$name => $mode,)+ + }; + mode + } + + /// Whether this tool requires LLVM to run + pub fn uses_llvm_tools(&self) -> bool { + match self { + $(Tool::$name => false $(|| $llvm)*,)+ + } + } + } + impl<'a> Builder<'a> { pub fn tool_exe(&self, tool: Tool) -> PathBuf { let stage = self.tool_default_stage(tool); @@ -324,17 +341,17 @@ macro_rules! tool { } tool!( - Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc; - ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc; - UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd; - Tidy, "src/tools/tidy", "tidy", Mode::Libstd; - Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd; - CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd; - Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest; - BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd; - RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd; - RustInstaller, "src/tools/rust-installer", "fabricate", Mode::Libstd; - RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::Libstd; + Rustbook, "src/tools/rustbook", "rustbook", Mode::ToolRustc; + ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::ToolRustc; + UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::ToolStd; + Tidy, "src/tools/tidy", "tidy", Mode::ToolStd; + Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::ToolStd; + CargoTest, "src/tools/cargotest", "cargotest", Mode::ToolStd; + Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTest, llvm_tools = true; + BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolStd; + RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolStd; + RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolStd; + RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::ToolStd; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -362,7 +379,7 @@ impl Step for RemoteTestServer { compiler: self.compiler, target: self.target, tool: "remote-test-server", - mode: Mode::Libstd, + mode: Mode::ToolStd, path: "src/tools/remote-test-server", is_ext_tool: false, extra_features: Vec::new(), @@ -414,6 +431,7 @@ impl Step for Rustdoc { let mut cargo = prepare_tool_cargo(builder, build_compiler, + Mode::ToolRustc, target, "build", "src/tools/rustdoc"); @@ -430,8 +448,8 @@ impl Step for Rustdoc { // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" // rustdoc a different name. - let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target) - .join(exe("rustdoc-tool-binary", &target_compiler.host)); + let tool_rustdoc = builder.cargo_out(build_compiler, Mode::ToolRustc, target) + .join(exe("rustdoc_tool_binary", &target_compiler.host)); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { @@ -485,7 +503,7 @@ impl Step for Cargo { compiler: self.compiler, target: self.target, tool: "cargo", - mode: Mode::Librustc, + mode: Mode::ToolRustc, path: "src/tools/cargo", is_ext_tool: false, extra_features: Vec::new(), @@ -533,7 +551,7 @@ macro_rules! tool_extended { compiler: $sel.compiler, target: $sel.target, tool: $tool_name, - mode: Mode::Librustc, + mode: Mode::ToolRustc, path: $path, extra_features: $sel.extra_features, is_ext_tool: true, @@ -575,7 +593,7 @@ impl<'a> Builder<'a> { pub fn tool_cmd(&self, tool: Tool) -> Command { let mut cmd = Command::new(self.tool_exe(tool)); let compiler = self.compiler(self.tool_default_stage(tool), self.config.build); - self.prepare_tool_cmd(compiler, &mut cmd); + self.prepare_tool_cmd(compiler, tool, &mut cmd); cmd } @@ -583,11 +601,11 @@ impl<'a> Builder<'a> { /// /// Notably this munges the dynamic library lookup path to point to the /// right location to run `compiler`. - fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) { + fn prepare_tool_cmd(&self, compiler: Compiler, tool: Tool, cmd: &mut Command) { let host = &compiler.host; let mut lib_paths: Vec = vec![ PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)), - self.cargo_out(compiler, Mode::Tool, *host).join("deps"), + self.cargo_out(compiler, tool.get_mode(), *host).join("deps"), ]; // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make @@ -610,17 +628,19 @@ impl<'a> Builder<'a> { // Add the llvm/bin directory to PATH since it contains lots of // useful, platform-independent tools - if let Some(llvm_bin_path) = self.llvm_bin_path() { - if host.contains("windows") { - // On Windows, PATH and the dynamic library path are the same, - // so we just add the LLVM bin path to lib_path - lib_paths.push(llvm_bin_path); - } else { - let old_path = env::var_os("PATH").unwrap_or_default(); - let new_path = env::join_paths(iter::once(llvm_bin_path) - .chain(env::split_paths(&old_path))) - .expect("Could not add LLVM bin path to PATH"); - cmd.env("PATH", new_path); + if tool.uses_llvm_tools() { + if let Some(llvm_bin_path) = self.llvm_bin_path() { + if host.contains("windows") { + // On Windows, PATH and the dynamic library path are the same, + // so we just add the LLVM bin path to lib_path + lib_paths.push(llvm_bin_path); + } else { + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = env::join_paths(iter::once(llvm_bin_path) + .chain(env::split_paths(&old_path))) + .expect("Could not add LLVM bin path to PATH"); + cmd.env("PATH", new_path); + } } } diff --git a/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile b/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile new file mode 100644 index 0000000000..34c6e640ab --- /dev/null +++ b/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile @@ -0,0 +1,36 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + xz-utils \ + bzip2 \ + libssl-dev \ + pkg-config + + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV BASE_URL=https://releases.linaro.org/components/toolchain/binaries/latest/armeb-eabi/ +ENV GCC_LINARO=gcc-linaro-7.2.1-2017.11-x86_64_armeb-eabi + +RUN curl -sL $BASE_URL/$GCC_LINARO.tar.xz | tar -xJ + +ENV PATH=$PATH:/$GCC_LINARO/bin + +ENV TARGET=armebv7r-none-eabihf + +ENV CC_armebv7r_none_eabihf=armeb-eabi-gcc \ + CFLAGS_armebv7r_none_eabihf="-march=armv7-r" + +ENV RUST_CONFIGURE_ARGS --disable-docs + +ENV SCRIPT python2.7 ../x.py dist --target $TARGET diff --git a/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile new file mode 100644 index 0000000000..952c265a13 --- /dev/null +++ b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-sparc64-linux-gnu \ + libssl-dev \ + pkg-config + + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV HOSTS=sparc64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 0ec57ee088..d591fb28f3 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -29,13 +29,13 @@ ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig WORKDIR /tmp -COPY dist-i686-linux/shared.sh dist-i686-linux/build-binutils.sh /tmp/ +COPY dist-x86_64-linux/shared.sh /tmp/ # We need a build of openssl which supports SNI to download artifacts from # static.rust-lang.org. This'll be used to link into libcurl below (and used # later as well), so build a copy of OpenSSL with dynamic libraries into our # generic root. -COPY dist-i686-linux/build-openssl.sh /tmp/ +COPY dist-x86_64-linux/build-openssl.sh /tmp/ RUN ./build-openssl.sh # The `curl` binary on CentOS doesn't support SNI which is needed for fetching @@ -44,36 +44,43 @@ RUN ./build-openssl.sh # # Note that we also disable a bunch of optional features of curl that we don't # really need. -COPY dist-i686-linux/build-curl.sh /tmp/ +COPY dist-x86_64-linux/build-curl.sh /tmp/ RUN ./build-curl.sh # binutils < 2.22 has a bug where the 32-bit executables it generates # immediately segfault in Rust, so we need to install our own binutils. # # See https://github.com/rust-lang/rust/issues/20440 for more info +COPY dist-x86_64-linux/build-binutils.sh /tmp/ RUN ./build-binutils.sh -# Need a newer version of gcc than centos has to compile LLVM nowadays -COPY dist-i686-linux/build-gcc.sh /tmp/ -RUN ./build-gcc.sh - -# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ -COPY dist-i686-linux/build-python.sh /tmp/ -RUN ./build-python.sh - -# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for -# cloning, so download and build it here. -COPY dist-i686-linux/build-git.sh /tmp/ -RUN ./build-git.sh - # libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS # only has 2.6.4, so build our own -COPY dist-i686-linux/build-cmake.sh /tmp/ +COPY dist-x86_64-linux/build-cmake.sh /tmp/ RUN ./build-cmake.sh +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY dist-x86_64-linux/build-gcc.sh /tmp/ +RUN ./build-gcc.sh + +# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ +COPY dist-x86_64-linux/build-python.sh /tmp/ +RUN ./build-python.sh + +# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# clang/clang++ compilers. +COPY dist-x86_64-linux/build-clang.sh /tmp/ +RUN ./build-clang.sh +ENV CC=clang CXX=clang++ + +# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for +# cloning, so download and build it here. +COPY dist-x86_64-linux/build-git.sh /tmp/ +RUN ./build-git.sh + # for sanitizers, we need kernel headers files newer than the ones CentOS ships # with so we install newer ones here -COPY dist-i686-linux/build-headers.sh /tmp/ +COPY dist-x86_64-linux/build-headers.sh /tmp/ RUN ./build-headers.sh COPY scripts/sccache.sh /scripts/ @@ -84,11 +91,21 @@ ENV HOSTS=i686-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --set target.i686-unknown-linux-gnu.linker=clang \ + --build=i686-unknown-linux-gnu ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS +ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang -# This is the only builder which will create source tarballs -ENV DIST_SRC 1 +# This was added when we switched from gcc to clang. It's not clear why this is +# needed unfortunately, but without this the stage1 bootstrap segfaults +# somewhere inside of a build script. The build ends up just hanging instead of +# actually killing the process that segfaulted, but if the process is run +# manually in a debugger the segfault is immediately seen as well as the +# misaligned stack access. +# +# Added in #50200 there's some more logs there +ENV CFLAGS -mstackrealign # When we build cargo in this container, we don't want it to use the system # libcurl, instead it should compile its own. diff --git a/src/ci/docker/dist-i686-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh deleted file mode 100755 index f4bdbd80d0..0000000000 --- a/src/ci/docker/dist-i686-linux/build-binutils.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -source shared.sh - -curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - - -mkdir binutils-build -cd binutils-build -hide_output ../binutils-2.25.1/configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf binutils-build -rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-i686-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh deleted file mode 100755 index 9a3763d421..0000000000 --- a/src/ci/docker/dist-i686-linux/build-cmake.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - - -mkdir cmake-build -cd cmake-build -hide_output ../cmake-3.6.3/configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf cmake-build -rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-i686-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh deleted file mode 100755 index edf3175b81..0000000000 --- a/src/ci/docker/dist-i686-linux/build-curl.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -VERSION=7.51.0 - -curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - - -mkdir curl-build -cd curl-build -hide_output ../curl-$VERSION/configure \ - --prefix=/rustroot \ - --with-ssl=/rustroot \ - --disable-sspi \ - --disable-gopher \ - --disable-smtp \ - --disable-smb \ - --disable-imap \ - --disable-pop3 \ - --disable-tftp \ - --disable-telnet \ - --disable-manual \ - --disable-dict \ - --disable-rtsp \ - --disable-ldaps \ - --disable-ldap -hide_output make -j10 -hide_output make install - -cd .. -rm -rf curl-build -rm -rf curl-$VERSION -yum erase -y curl diff --git a/src/ci/docker/dist-i686-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh deleted file mode 100755 index 08020e533f..0000000000 --- a/src/ci/docker/dist-i686-linux/build-gcc.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -source shared.sh - -GCC=4.8.5 - -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - -cd gcc-$GCC - -# FIXME(#49246): Remove the `sed` below. -# -# On 2018 March 21st, two Travis builders' cache for Docker are suddenly invalidated. Normally this -# is fine, because we just need to rebuild the Docker image. However, it reveals a network issue: -# downloading from `ftp://gcc.gnu.org/` from Travis (using passive mode) often leads to "Connection -# timed out" error, and even when the download completed, the file is usually corrupted. This causes -# nothing to be landed that day. -# -# We observed that the `gcc-4.8.5.tar.bz2` above can be downloaded successfully, so as a stability -# improvement we try to download from the HTTPS mirror instead. Turns out this uncovered the third -# bug: the host `gcc.gnu.org` and `cygwin.com` share the same IP, and the TLS certificate of the -# latter host is presented to `wget`! Therefore, we choose to download from the insecure HTTP server -# instead here. -# -sed -i'' 's|ftp://gcc\.gnu\.org/|http://gcc.gnu.org/|g' ./contrib/download_prerequisites - -./contrib/download_prerequisites -mkdir ../gcc-build -cd ../gcc-build -hide_output ../gcc-$GCC/configure \ - --prefix=/rustroot \ - --enable-languages=c,c++ -hide_output make -j10 -hide_output make install -ln -nsf gcc /rustroot/bin/cc - -cd .. -rm -rf gcc-build -rm -rf gcc-$GCC -yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-i686-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh deleted file mode 100755 index aa31f50ba0..0000000000 --- a/src/ci/docker/dist-i686-linux/build-git.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - - -cd git-2.10.0 -make configure -hide_output ./configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-i686-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh deleted file mode 100755 index 2f15114d6f..0000000000 --- a/src/ci/docker/dist-i686-linux/build-headers.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x - -cd linux-3.2.84 -hide_output make mrproper -hide_output make INSTALL_HDR_PATH=dest headers_install - -find dest/include \( -name .install -o -name ..install.cmd \) -delete -yes | cp -fr dest/include/* /usr/include - -cd .. -rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-i686-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh deleted file mode 100755 index e7226ace02..0000000000 --- a/src/ci/docker/dist-i686-linux/build-openssl.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -VERSION=1.0.2k -URL=https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/openssl-$VERSION.tar.gz - -curl $URL | tar xzf - - -cd openssl-$VERSION -hide_output ./config --prefix=/rustroot shared -fPIC -hide_output make -j10 -hide_output make install -cd .. -rm -rf openssl-$VERSION - -# Make the system cert collection available to the new install. -ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-i686-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh deleted file mode 100755 index c6b8cdde4b..0000000000 --- a/src/ci/docker/dist-i686-linux/build-python.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ - tar xzf - - -mkdir python-build -cd python-build - -# Gotta do some hackery to tell python about our custom OpenSSL build, but other -# than that fairly normal. -CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ - hide_output ../Python-2.7.12/configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf python-build -rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-i686-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh deleted file mode 100644 index 97e6d2908c..0000000000 --- a/src/ci/docker/dist-i686-linux/shared.sh +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2017 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -hide_output() { - set +x - on_err=" -echo ERROR: An error was encountered with the build. -cat /tmp/build.log -exit 1 -" - trap "$on_err" ERR - bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & - PING_LOOP_PID=$! - $@ &> /tmp/build.log - trap - ERR - kill $PING_LOOP_PID - set -x -} diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 28c97e8c6d..5726fab752 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -29,7 +29,7 @@ ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig WORKDIR /tmp -COPY dist-x86_64-linux/shared.sh dist-x86_64-linux/build-binutils.sh /tmp/ +COPY dist-x86_64-linux/shared.sh /tmp/ # We need a build of openssl which supports SNI to download artifacts from # static.rust-lang.org. This'll be used to link into libcurl below (and used @@ -51,9 +51,15 @@ RUN ./build-curl.sh # immediately segfault in Rust, so we need to install our own binutils. # # See https://github.com/rust-lang/rust/issues/20440 for more info +COPY dist-x86_64-linux/build-binutils.sh /tmp/ RUN ./build-binutils.sh -# Need a newer version of gcc than centos has to compile LLVM nowadays +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY dist-x86_64-linux/build-cmake.sh /tmp/ +RUN ./build-cmake.sh + +# Build a version of gcc capable of building LLVM 6 COPY dist-x86_64-linux/build-gcc.sh /tmp/ RUN ./build-gcc.sh @@ -61,16 +67,17 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh +# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# clang/clang++ compilers. +COPY dist-x86_64-linux/build-clang.sh /tmp/ +RUN ./build-clang.sh +ENV CC=clang CXX=clang++ + # Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for # cloning, so download and build it here. COPY dist-x86_64-linux/build-git.sh /tmp/ RUN ./build-git.sh -# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS -# only has 2.6.4, so build our own -COPY dist-x86_64-linux/build-cmake.sh /tmp/ -RUN ./build-cmake.sh - # for sanitizers, we need kernel headers files newer than the ones CentOS ships # with so we install newer ones here COPY dist-x86_64-linux/build-headers.sh /tmp/ @@ -85,8 +92,10 @@ ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ --enable-sanitizers \ --enable-profiler \ - --enable-compiler-docs + --enable-compiler-docs \ + --set target.x86_64-unknown-linux-gnu.linker=clang ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS +ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs ENV DIST_SRC 1 diff --git a/src/ci/docker/dist-x86_64-linux/build-clang.sh b/src/ci/docker/dist-x86_64-linux/build-clang.sh new file mode 100755 index 0000000000..b0c27aa45b --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-clang.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Copyright 2017 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 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +LLVM=6.0.0 + +mkdir clang +cd clang + +curl https://releases.llvm.org/$LLVM/llvm-$LLVM.src.tar.xz | \ + xz -d | \ + tar xf - + +cd llvm-$LLVM.src + +mkdir -p tools/clang + +curl https://releases.llvm.org/$LLVM/cfe-$LLVM.src.tar.xz | \ + xz -d | \ + tar xf - -C tools/clang --strip-components=1 + +mkdir ../clang-build +cd ../clang-build + +# For whatever reason the default set of include paths for clang is different +# than that of gcc. As a result we need to manually include our sysroot's +# include path, /rustroot/include, to clang's default include path. +# +# Alsow there's this weird oddity with gcc where there's an 'include-fixed' +# directory that it generates. It turns out [1] that Centos 5's headers are so +# old that they're incompatible with modern C semantics. While gcc automatically +# fixes that clang doesn't account for this. Tell clang to manually include the +# fixed headers so we can successfully compile code later on. +# +# [1]: https://sourceware.org/ml/crossgcc/2008-11/msg00028.html +INC="/rustroot/include" +INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/4.8.5/include-fixed" +INC="$INC:/usr/include" + +hide_output \ + cmake ../llvm-$LLVM.src \ + -DCMAKE_C_COMPILER=/rustroot/bin/gcc \ + -DCMAKE_CXX_COMPILER=/rustroot/bin/g++ \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/rustroot \ + -DLLVM_TARGETS_TO_BUILD=X86 \ + -DC_INCLUDE_DIRS="$INC" + +hide_output make -j10 +hide_output make install + +cd ../.. +rm -rf clang diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh index 08020e533f..62ea2506f4 100755 --- a/src/ci/docker/dist-x86_64-linux/build-gcc.sh +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -42,7 +42,6 @@ hide_output ../gcc-$GCC/configure \ --enable-languages=c,c++ hide_output make -j10 hide_output make install -ln -nsf gcc /rustroot/bin/cc cd .. rm -rf gcc-build diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c470ae7eb3..8913fdaa88 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -36,8 +36,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then s3url="s3://$SCCACHE_BUCKET/docker/$cksum" url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum" echo "Attempting to download $s3url" + rm -f /tmp/rustci_docker_cache set +e - loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/') + retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url" + loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/') set -e echo "Downloaded containers:\n$loaded_images" fi @@ -116,6 +118,10 @@ fi # goes ahead and sets it for all builders. args="$args --privileged" +if [ "$CI" != "" ]; then + args="$args --dns 8.8.8.8 --dns 8.8.4.4 --dns 1.1.1.1 --dns 1.0.0.1" +fi + exec docker \ run \ --volume "$root_dir:/checkout:ro" \ diff --git a/src/ci/docker/x86_64-gnu-tools/checkregression.py b/src/ci/docker/x86_64-gnu-tools/checkregression.py index df791d1264..208aab434c 100755 --- a/src/ci/docker/x86_64-gnu-tools/checkregression.py +++ b/src/ci/docker/x86_64-gnu-tools/checkregression.py @@ -18,6 +18,7 @@ if __name__ == '__main__': os_name = sys.argv[1] toolstate_file = sys.argv[2] current_state = sys.argv[3] + verb = sys.argv[4] # 'regressed' or 'changed' with open(toolstate_file, 'r') as f: toolstate = json.load(f) @@ -29,10 +30,17 @@ if __name__ == '__main__': tool = cur['tool'] state = cur[os_name] new_state = toolstate.get(tool, '') - if new_state < state: + if verb == 'regressed': + updated = new_state < state + elif verb == 'changed': + updated = new_state != state + else: + print('Unknown verb {}'.format(updated)) + sys.exit(2) + if updated: print( - 'Error: The state of "{}" has regressed from "{}" to "{}"' - .format(tool, state, new_state) + 'The state of "{}" has {} from "{}" to "{}"' + .format(tool, verb, state, new_state) ) regressed = True diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index d37f17afc9..56e637249f 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -23,6 +23,8 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))" touch "$TOOLSTATE_FILE" +# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE + set +e python2.7 "$X_PY" test --no-fail-fast \ src/doc/book \ @@ -30,12 +32,15 @@ python2.7 "$X_PY" test --no-fail-fast \ src/doc/reference \ src/doc/rust-by-example \ src/tools/rls \ - src/tools/rustfmt + src/tools/rustfmt \ + src/tools/miri \ + src/tools/clippy set -e cat "$TOOLSTATE_FILE" echo +# This function checks that if a tool's submodule changed, the tool's state must improve verify_status() { echo "Verifying status of $1..." if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then @@ -55,33 +60,61 @@ verify_status() { fi } +# deduplicates the submodule check and the assertion that on beta some tools MUST be passing +check_dispatch() { + if [ "$1" = submodule_changed ]; then + # ignore $2 (branch id) + verify_status $3 $4 + elif [ "$2" = beta ]; then + echo "Requiring test passing for $3..." + if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then + exit 4 + fi + fi +} + +# list all tools here +status_check() { + check_dispatch $1 beta book src/doc/book + check_dispatch $1 beta nomicon src/doc/nomicon + check_dispatch $1 beta reference src/doc/reference + check_dispatch $1 beta rust-by-example src/doc/rust-by-example + check_dispatch $1 beta rls src/tool/rls + check_dispatch $1 beta rustfmt src/tool/rustfmt + # these tools are not required for beta to successfully branch + check_dispatch $1 nightly clippy-driver src/tool/clippy + check_dispatch $1 nightly miri src/tool/miri +} + # If this PR is intended to update one of these tools, do not let the build pass # when they do not test-pass. -verify_status book src/doc/book -verify_status nomicon src/doc/nomicon -verify_status reference src/doc/reference -verify_status rust-by-example src/doc/rust-by-example -verify_status rls src/tool/rls -verify_status rustfmt src/tool/rustfmt +status_check "submodule_changed" + +CHECK_NOT="$(readlink -f "$(dirname $0)/checkregression.py")" +change_toolstate() { + # only update the history + if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then + echo 'Toolstate is not changed. Not updating.' + else + if [ $SIX_WEEK_CYCLE -eq 5 ]; then + python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed + fi + sed -i "1 a\\ +$COMMIT\t$(cat "$TOOLSTATE_FILE") +" "history/$OS.tsv" + fi +} if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then . "$(dirname $0)/repo.sh" MESSAGE_FILE=$(mktemp -t msg.XXXXXX) echo "($OS CI update)" > "$MESSAGE_FILE" - commit_toolstate_change "$MESSAGE_FILE" \ - sed -i "1 a\\ -$COMMIT\t$(cat "$TOOLSTATE_FILE") -" "history/$OS.tsv" - # if we are at the last week in the 6-week release cycle, reject any kind of regression. - if [ $SIX_WEEK_CYCLE -eq 5 ]; then - python2.7 "$(dirname $0)/checkregression.py" \ - "$OS" "$TOOLSTATE_FILE" "rust-toolstate/_data/latest.json" - fi + commit_toolstate_change "$MESSAGE_FILE" change_toolstate rm -f "$MESSAGE_FILE" exit 0 fi -if grep -q fail "$TOOLSTATE_FILE"; then - exit 4 -fi +# abort compilation if an important tool doesn't build +# (this code is reachable if not on the nightly channel) +status_check "beta_required" diff --git a/src/ci/docker/x86_64-gnu-tools/repo.sh b/src/ci/docker/x86_64-gnu-tools/repo.sh index c10afef753..807e6fb7b6 100644 --- a/src/ci/docker/x86_64-gnu-tools/repo.sh +++ b/src/ci/docker/x86_64-gnu-tools/repo.sh @@ -60,7 +60,7 @@ commit_toolstate_change() { OLDFLAGS="$-" set -eu - git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com' + git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com' git config --global user.name 'Rust Toolstate Update' git config --global credential.helper store printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \ diff --git a/src/ci/run.sh b/src/ci/run.sh index 4cff013c67..44db6b92c9 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -27,10 +27,8 @@ fi ci_dir=`cd $(dirname $0) && pwd` source "$ci_dir/shared.sh" -if [ "$TRAVIS" == "true" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" -else - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings" +if [ "$TRAVIS" != "true" ] || [ "$TRAVIS_BRANCH" == "auto" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache" @@ -48,7 +46,7 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=stable +export RUST_RELEASE_CHANNEL=beta if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 4a08683e3e..bb6945f0fd 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -21,11 +21,12 @@ function retry { while true; do "$@" && break || { if [[ $n -lt $max ]]; then + sleep $n # don't retry immediately ((n++)) echo "Command failed. Attempt $n/$max:" else echo "The command has failed after $n attempts." - exit 1 + return 1 fi } done diff --git a/src/doc/book/.github/ISSUE_TEMPLATE.md b/src/doc/book/.github/ISSUE_TEMPLATE.md index 619f4ff485..dcd59a807d 100644 --- a/src/doc/book/.github/ISSUE_TEMPLATE.md +++ b/src/doc/book/.github/ISSUE_TEMPLATE.md @@ -9,18 +9,9 @@ This version of the book is under development, please file issues liberally! ### Second edition -For the second edition, we are currently working with No Starch Press to bring -it to print. Chapters go through a number of stages in the editing process, and -once they've gotten to the layout stage, they're effectively frozen. - -For chapters that have gotten to the layout stage, we will likely only be -accepting changes that correct factual errors or major problems and not, for -example, minor wording changes. - -Scroll all the way to the right on https://github.com/rust-lang/book/projects/1 -to see which chapters have been frozen. - -Please see CONTRIBUTING.md for more details. +No Starch Press has brought the second edition to print. Bugs containing +factual errors will be documented as errata; bugs for wording changes or +other small corrections should be filed against the 2018 edition. ### First edition diff --git a/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md b/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md index c25844d737..bda1589336 100644 --- a/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md +++ b/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md @@ -11,18 +11,9 @@ ultimately wouldn't accept. ### Second edition -For the second edition, we are currently working with No Starch Press to bring -it to print. Chapters go through a number of stages in the editing process, and -once they've gotten to the layout stage, they're effectively frozen. - -For chapters that have gotten to the layout stage, we will likely only be -accepting changes that correct factual errors or major problems and not, for -example, minor wording changes. - -Scroll all the way to the right on https://github.com/rust-lang/book/projects/1 -to see which chapters have been frozen. - -Please see CONTRIBUTING.md for more details. +No Starch Press has brought the second edition to print. Pull requests fixing +factual errors will be accepted and documented as errata; pull requests changing +wording or other small corrections should be made against the 2018 edition instead. ### First edition diff --git a/src/doc/book/2018-edition/dictionary.txt b/src/doc/book/2018-edition/dictionary.txt deleted file mode 100644 index 875713cc8b..0000000000 --- a/src/doc/book/2018-edition/dictionary.txt +++ /dev/null @@ -1,502 +0,0 @@ -personal_ws-1.1 en 0 utf-8 -abcabcabc -abcd -abcdefghijklmnopqrstuvwxyz -adaptor -adaptors -AddAssign -Addr -aggregator -AGraph -aliasability -alignof -alloc -allocator -Amir -anotherusername -APIs -app's -aren -args -associativity -async -atomics -AveragedCollection -backend -backported -backtrace -backtraces -BACKTRACE -Backtraces -Baz’s -benchmarking -bioinformatics -bitand -BitAnd -BitAndAssign -bitor -BitOr -BitOrAssign -bitwise -Bitwise -bitxor -BitXor -BitXorAssign -Bjarne -Boehm -bool -Boolean -Booleans -Bors -BorrowMutError -BTreeSet -BuildHasher -Cacher -Cagain -callsite -CamelCase -cargodoc -ChangeColor -ChangeColorMessage -charset -choo -chXX -chYY -coercions -combinator -ConcreteType -config -Config -const -constant's -copyeditor -couldn -CPUs -cratesio -CRLF -cryptocurrencies -cryptographic -cryptographically -CStr -CString -ctrl -Ctrl -customizable -CustomSmartPointer -CustomSmartPointers -data’s -deallocate -deallocated -deallocating -deallocation -debuginfo -decrementing -deps -deref -Deref -dereference -Dereference -dereferenced -dereferences -dereferencing -DerefMut -DeriveInput -destructor -destructure -destructured -destructures -destructuring -Destructuring -deterministically -DevOps -didn -Dobrý -doccargo -doccratesio -DOCTYPE -doesn -disambiguating -DivAssign -DraftPost -DSTs -ebooks -Edsger -egular -else's -emoji -encodings -enum -Enum -enums -enum's -Enums -eprintln -Erlang -ErrorKind -Executables -expr -extern -favicon -FFFD -FFFF -figcaption -fieldname -filename -Filename -filesystem -Filesystem -filesystems -Firefox -FnBox -FnMut -FnOnce -formatter -formatters -FrenchToast -FromIterator -frontend -getter -GGraph -GitHub -gitignore -grapheme -Grapheme -growable -gzip -hardcode -hardcoded -hardcoding -hasher -hashers -HashMap -HashSet -Haskell -hasn -HelloMacro -helloworld -HelloWorld -HelloWorldName -Hmmm -Hoare -Hola -homogenous -html -hyperoptimize -Iceburgh -ident -IDE -IDEs -IDE's -IEEE -impl -implementor -implementors -ImportantExcerpt -incrementing -IndexMut -indices -init -initializer -inline -instantiation -internet -IntoIterator -InvalidDigit -invariants -ioerror -iokind -ioresult -iostdin -IpAddr -IpAddrKind -irst -isize -iter -iterator's -JavaScript -JoinHandle -Kay's -kinded -lang -latin -liballoc -libc -libcollections -libcore -libpanic -librarys -libreoffice -libstd -lifecycle -LimitTracker -LLVM -lobally -locators -LockResult -login -lookup -loopback -lossy -lval -macOS -Matsakis -mathematic -memoization -metadata -Metadata -metaprogramming -mibbit -Mibbit -millis -minigrep -mixup -mkdir -MockMessenger -modifiability -modularity -monomorphization -Monomorphization -monomorphized -MoveMessage -Mozilla -mpsc -msvc -MulAssign -multibyte -multithreaded -mutex -mutex's -Mutex -mutexes -Mutexes -MutexGuard -MyBox -namespace -namespaced -namespaces -namespacing -natively -newfound -NewJob -NewsArticle -NewThread -newtype -newtypes -nitty -nocapture -nomicon -nondeterministic -nonequality -nongeneric -NotFound -null's -OCaml -offsetof -online -OpenGL -optimizations -OptionalFloatingPointNumber -OptionalNumber -OsStr -OsString -other's -OutlinePrint -overloadable -overread -param -parameterize -ParseIntError -PartialEq -PartialOrd -PendingReview -PendingReviewPost -PlaceholderType -polymorphism -PoolCreationError -portia -powershell -PowerShell -powi -preprocessing -Preprocessing -preprocessor -PrimaryColor -println -priv -proc -pthreads -pushups -QuitMessage -quux -RAII -randcrate -RangeFrom -RangeTo -RangeFull -README -READMEs -rect -recurse -recv -redeclaring -Refactoring -refactor -refactoring -refcell -RefCell -RefMut -refutability -reimplement -RemAssign -repr -representable -request's -resizes -resizing -retweet -rewordings -rint -ripgrep -runnable -runtime -runtimes -Rustacean -Rustaceans -rUsT -rustc -rustdoc -Rustonomicon -rustfmt -rustup -screenshot -searchstring -SecondaryColor -SelectBox -semver -SemVer -serde -ShlAssign -ShrAssign -shouldn -Simula -situps -sizeof -Smalltalk -snuck -someproject -someusername -SPDX -spdx -SpreadsheetCell -sqrt -stackoverflow -startup -StaticRef -stderr -stdin -Stdin -stdlib -stdout -steveklabnik's -stringify -Stroustrup -Stroustrup's -struct -Struct -structs -struct's -Structs -SubAssign -subclasses -subcommand -subcommands -subdirectories -subdirectory -submodule -submodules -Submodules -suboptimal -substring -subteams -subtree -subtyping -supertrait -supertraits -TcpListener -TcpStream -templating -test's -TextField -That'd -there'd -ThreadPool -timestamp -Tiếng -timeline -tlborm -TODO -TokenStream -toml -TOML -toolchain -toolchains -ToString -tradeoff -tradeoffs -TrafficLight -transcoding -trpl -tuesday -tuple -tuples -turbofish -Turon -typeof -TypeName -UFCS -unary -Unary -uncomment -Uncomment -unevaluated -Uninstalling -uninstall -unix -unpopulated -unoptimized -UnsafeCell -unsafety -unsized -unsynchronized -URIs -UsefulType -username -USERPROFILE -usize -UsState -utils -vals -variable's -variant's -vers -versa -Versioning -visualstudio -Vlissides -vtable -wasn -WeatherForecast -WebSocket -whitespace -wildcard -wildcards -workflow -workspace -workspaces -Workspaces -wouldn -writeln -WriteMessage -xpression -yyyy -ZipImpl diff --git a/src/doc/book/2018-edition/src/SUMMARY.md b/src/doc/book/2018-edition/src/SUMMARY.md index 1ca086328c..13e3ae6791 100644 --- a/src/doc/book/2018-edition/src/SUMMARY.md +++ b/src/doc/book/2018-edition/src/SUMMARY.md @@ -128,5 +128,4 @@ - [C - Derivable Traits](appendix-03-derivable-traits.md) - [D - Macros](appendix-04-macros.md) - [E - Translations](appendix-05-translation.md) - - [F - Newest Features](appendix-06-newest-features.md) - - [G - How Rust is Made and “Nightly Rust”](appendix-07-nightly-rust.md) + - [F - How Rust is Made and “Nightly Rust”](appendix-06-nightly-rust.md) diff --git a/src/doc/book/2018-edition/src/appendix-01-keywords.md b/src/doc/book/2018-edition/src/appendix-01-keywords.md index 319f6e3751..077b92ba6f 100644 --- a/src/doc/book/2018-edition/src/appendix-01-keywords.md +++ b/src/doc/book/2018-edition/src/appendix-01-keywords.md @@ -1,19 +1,21 @@ ## Appendix A: Keywords -The following is a list of keywords that are reserved for current or future use -by the Rust language. As such, these may not be used as identifiers, such as +The following list contains keywords that are reserved for current or future +use by the Rust language. As such, they cannot be used as identifiers, such as names of functions, variables, parameters, struct fields, modules, crates, constants, macros, static values, attributes, types, traits, or lifetimes. ### Keywords Currently in Use -* `as` - perform primitive casting, disambiguate the specific trait - containing an item, or rename items in `use` and `extern crate` statements +The following keywords currently have the functionality described. + +* `as` - perform primitive casting, disambiguate the specific trait containing + an item, or rename items in `use` and `extern crate` statements * `break` - exit a loop immediately * `const` - define constant items or constant raw pointers * `continue` - continue to the next loop iteration -* `crate` - link an external crate or a macro variable representing the crate - in which the macro is defined +* `crate` - link an external crate or a macro variable representing the crate in + which the macro is defined * `else` - fallback for `if` and `if let` control flow constructs * `enum` - define an enumeration * `extern` - link an external crate, function, or variable @@ -46,20 +48,10 @@ constants, macros, static values, attributes, types, traits, or lifetimes. * `where` - denote clauses that constrain a type * `while` - loop conditionally based on the result of an expression - - - ### Keywords Reserved for Future Use -These keywords do not have any functionality, but are reserved by Rust for -potential future use. +The following keywords do not have any functionality but are reserved by Rust +for potential future use. * `abstract` * `alignof` diff --git a/src/doc/book/2018-edition/src/appendix-02-operators.md b/src/doc/book/2018-edition/src/appendix-02-operators.md index 73c429163b..3538c07b1d 100644 --- a/src/doc/book/2018-edition/src/appendix-02-operators.md +++ b/src/doc/book/2018-edition/src/appendix-02-operators.md @@ -1,172 +1,204 @@ ## Appendix B: Operators and Symbols - - - -This appendix is a glossary of Rust’s syntax, including operators and other -symbols that appear by themselves or in the context of paths, generics, trait -bounds, macros, attributes, comments, tuples, and brackets. +This appendix contains a glossary of Rust’s syntax, including operators and +other symbols that appear by themselves or in the context of paths, generics, +trait bounds, macros, attributes, comments, tuples, and brackets. ### Operators -The following lists the operators in Rust, an example of how the operator would +Table B-1 contains the operators in Rust, an example of how the operator would appear in context, a short explanation, and whether that operator is overloadable. If an operator is overloadable, the relevant trait to use to overload that operator is listed. - +Table B-1: Operators -* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion. -* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). -* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`). -* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). -* `%=` (`var %= expr`): arithmetic remainder and assignment. Overloadable (`RemAssign`). -* `&` (`&expr`, `&mut expr`): borrow. -* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. -* `&` (`expr & expr`): bitwise AND. Overloadable (`BitAnd`). -* `&=` (`var &= expr`): bitwise AND and assignment. Overloadable (`BitAndAssign`). -* `&&` (`expr && expr`): logical AND. -* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). -* `*` (`*expr`): dereference. -* `*` (`*const type`, `*mut type`): raw pointer. -* `*=` (`var *= expr`): arithmetic multiplication and assignment. Overloadable (`MulAssign`). -* `+` (`trait + trait`, `'a + trait`): compound type constraint. -* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). -* `+=` (`var += expr`): arithmetic addition and assignment. Overloadable (`AddAssign`). -* `,`: argument and element separator. -* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). -* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). -* `-=` (`var -= expr`): arithmetic subtraction and assignment. Overloadable (`SubAssign`). -* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. -* `.` (`expr.ident`): member access. -* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. -* `..` (`..expr`): struct literal update syntax. -* `..` (`variant(x, ..)`, `struct_type { x, .. }`): “and the rest” pattern binding. -* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. -* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). -* `/=` (`var /= expr`): arithmetic division and assignment. Overloadable (`DivAssign`). -* `:` (`pat: type`, `ident: type`): constraints. -* `:` (`ident: expr`): struct field initializer. -* `:` (`'a: loop {…}`): loop label. -* `;`: statement and item terminator. -* `;` (`[…; len]`): part of fixed-size array syntax -* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). -* `<<=` (`var <<= expr`): left-shift and assignment. Overloadable (`ShlAssign`). -* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`). -* `<=` (`expr <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`). -* `=` (`var = expr`, `ident = type`): assignment/equivalence. -* `==` (`expr == expr`): equality comparison. Overloadable (`PartialEq`). -* `=>` (`pat => expr`): part of match arm syntax. -* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`). -* `>=` (`expr >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`). -* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). -* `>>=` (`var >>= expr`): right-shift and assignment. Overloadable (`ShrAssign`). -* `@` (`ident @ pat`): pattern binding. -* `^` (`expr ^ expr`): bitwise exclusive OR. Overloadable (`BitXor`). -* `^=` (`var ^= expr`): bitwise exclusive OR and assignment. Overloadable (`BitXorAssign`). -* `|` (`pat | pat`): pattern alternatives. -* `|` (`|…| expr`): closures. -* `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`). -* `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`). -* `||` (`expr || expr`): logical OR. -* `_`: “ignored” pattern binding. Also used to make integer-literals readable. -* `?` (`expr?`): Error propagation. +| Operator | Example | Explanation | Overloadable? | +|----------|---------|-------------|---------------| +| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro expansion | | +| `!` | `!expr` | Bitwise or logical complement | `Not` | +| `!=` | `var != expr` | Nonequality comparison | `PartialEq` | +| `%` | `expr % expr` | Arithmetic remainder | `Rem` | +| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemAssign` | +| `&` | `&expr`, `&mut expr` | Borrow | | +| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | Borrowed pointer type | | +| `&` | `expr & expr` | Bitwise AND | `BitAnd` | +| `&=` | `var &= expr` | Bitwise AND and assignment | `BitAndAssign` | +| `&&` | `expr && expr` | Logical AND | | +| `*` | `expr * expr` | Arithmetic multiplication | `Mul` | +| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulAssign` | +| `*` | `*expr` | Dereference | | +| `*` | `*const type`, `*mut type` | Raw pointer | | +| `+` | `trait + trait`, `'a + trait` | Compound type constraint | | +| `+` | `expr + expr` | Arithmetic addition | `Add` | +| `+=` | `var += expr` | Arithmetic addition and assignment | `AddAssign` | +| `,` | `expr, expr` | Argument and element separator | | +| `-` | `- expr` | Arithmetic negation | `Neg` | +| `-` | `expr - expr` | Arithmetic subtraction | `Sub` | +| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubAssign` | +| `->` | `fn(...) -> type`, \|...\| -> type | Function and closure return type | | +| `.` | `expr.ident` | Member access | | +| `..` | `..`, `expr..`, `..expr`, `expr..expr` | Right-exclusive range literal | | +| `..` | `..expr` | Struct literal update syntax | | +| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “And the rest” pattern binding | | +| `...` | `expr...expr` | In a pattern: inclusive range pattern | | +| `/` | `expr / expr` | Arithmetic division | `Div` | +| `/=` | `var /= expr` | Arithmetic division and assignment | `DivAssign` | +| `:` | `pat: type`, `ident: type` | Constraints | | +| `:` | `ident: expr` | Struct field initializer | | +| `:` | `'a: loop {...}` | Loop label | | +| `;` | `expr;` | Statement and item terminator | | +| `;` | `[...; len]` | Part of fixed-size array syntax | | +| `<<` | `expr << expr` | Left-shift | `Shl` | +| `<<=` | `var <<= expr` | Left-shift and assignment | `ShlAssign` | +| `<` | `expr < expr` | Less than comparison | `PartialOrd` | +| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` | +| `=` | `var = expr`, `ident = type` | Assignment/equivalence | | +| `==` | `expr == expr` | Equality comparison | `PartialEq` | +| `=>` | `pat => expr` | Part of match arm syntax | | +| `>` | `expr > expr` | Greater than comparison | `PartialOrd` | +| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` | +| `>>` | `expr >> expr` | Right-shift | `Shr` | +| `>>=` | `var >>= expr` | Right-shift and assignment | `ShrAssign` | +| `@` | `ident @ pat` | Pattern binding | | +| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` | +| `^=` | `var ^= expr` | Bitwise exclusive OR and assignment | `BitXorAssign` | +| \| | pat \| pat | Pattern alternatives | | +| \| | expr \| expr | Bitwise OR | `BitOr` | +| \|= | var \|= expr | Bitwise OR and assignment | `BitOrAssign` | +| \|\| | expr \|\| expr | Logical OR | | +| `?` | `expr?` | Error propagation | | ### Non-operator Symbols - - +The following list contains all non-letters that don’t function as operators; +that is, they don’t behave like a function or method call. -The following lists all non-letters that don’t function as operators; that is, -they don’t behave like a function or method call. +Table B-2 shows symbols that appear on their own and are valid in a variety of +locations. -#### Standalone Syntax +Table B-2: Stand-Alone Syntax -* `'ident`: named lifetime or loop label -* `…u8`, `…i32`, `…f64`, `…usize`, *etc.*: numeric literal of specific type. -* `"…"`: string literal. -* `r"…"`, `r#"…"#`, `r##"…"##`, *etc.*: raw string literal, escape characters are not processed. -* `b"…"`: byte string literal, constructs a `[u8]` instead of a string. -* `br"…"`, `br#"…"#`, `br##"…"##`, *etc.*: raw byte string literal, combination of raw and byte string literal. -* `'…'`: character literal. -* `b'…'`: ASCII byte literal. -* `|…| expr`: closure. -* `!`: always empty bottom type for diverging functions. +| Symbol | Explanation | +|--------|-------------| +| `'ident` | Named lifetime or loop label | +| `...u8`, `...i32`, `...f64`, `...usize`, etc. | Numeric literal of specific type | +| `"..."` | String literal | +| `r"..."`, `r#"..."#`, `r##"..."##`, etc. | Raw string literal, escape characters not processed | +| `b"..."` | Byte string literal; constructs a `[u8]` instead of a string | +| `br"..."`, `br#"..."#`, `br##"..."##`, etc. | Raw byte string literal, combination of raw and byte string literal | +| `'...'` | Character literal | +| `b'...'` | ASCII byte literal | +| \|...\| expr | Closure | +| `!` | Always empty bottom type for diverging functions | +| `_` | “Ignored” pattern binding; also used to make integer literals readable | -#### Path-related Syntax +Table B-3 shows symbols that appear in the context of a path through the module +hierarchy to an item. -* `ident::ident`: namespace path. -* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). -* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). -* `super::path`: path relative to the parent of the current module. -* `type::ident`, `::ident`: associated constants, functions, and types. -* `::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). -* `trait::method(…)`: disambiguating a method call by naming the trait which defines it. -* `type::method(…)`: disambiguating a method call by naming the type for which it’s defined. -* `::method(…)`: disambiguating a method call by naming the trait *and* type. +Table B-3: Path-Related Syntax -#### Generics +| Symbol | Explanation | +|--------|-------------| +| `ident::ident` | Namespace path | +| `::path` | Path relative to the crate root (i.e., an explicitly absolute path) | +| `self::path` | Path relative to the current module (i.e., an explicitly relative path). +| `super::path` | Path relative to the parent of the current module | +| `type::ident`, `::ident` | Associated constants, functions, and types | +| `::...` | Associated item for a type that cannot be directly named (e.g., `<&T>::...`, `<[T]>::...`, etc.) | +| `trait::method(...)` | Disambiguating a method call by naming the trait that defines it | +| `type::method(...)` | Disambiguating a method call by naming the type for which it’s defined | +| `::method(...)` | Disambiguating a method call by naming the trait and type | -* `path<…>` (*e.g.* `Vec`): specifies parameters to generic type *in a type*. -* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. Often referred to as *turbofish*. -* `fn ident<…> …`: define generic function. -* `struct ident<…> …`: define generic structure. -* `enum ident<…> …`: define generic enumeration. -* `impl<…> …`: define generic implementation. -* `for<…> type`: higher-ranked lifetime bounds. -* `type` (*e.g.* `Iterator`): a generic type where one or more associated types have specific assignments. +Table B-4 shows symbols that appear in the context of using generic type +parameters. -#### Trait Bound Constraints +Table B-4: Generics -* `T: U`: generic parameter `T` constrained to types that implement `U`. -* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type ‘outlives’ the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`. -* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones. -* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. -* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. -* `'a + trait`, `trait + trait`: compound type constraint. +| Symbol | Explanation | +|--------|-------------| +| `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec`) | +| `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., `"42".parse::()`) | +| `fn ident<...> ...` | Define generic function | +| `struct ident<...> ...` | Define generic structure | +| `enum ident<...> ...` | Define generic enumeration | +| `impl<...> ...` | Define generic implementation | +| `for<...> type` | Higher-ranked lifetime bounds | +| `type` | A generic type where one or more associated types have specific assignments (e.g., `Iterator`) | -#### Macros and Attributes +Table B-5 shows symbols that appear in the context of constraining generic type +parameters with trait bounds. -* `#[meta]`: outer attribute. -* `#![meta]`: inner attribute. -* `$ident`: macro substitution. -* `$ident:kind`: macro capture. -* `$(…)…`: macro repetition. +Table B-5: Trait Bound Constraints -#### Comments +| Symbol | Explanation | +|--------|-------------| +| `T: U` | Generic parameter `T` constrained to types that implement `U` | +| `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type cannot transitively contain any references with lifetimes shorter than `'a`) | +| `T : 'static` | Generic type `T` contains no borrowed references other than `'static` ones | +| `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` | +| `T: ?Sized` | Allow generic type parameter to be a dynamically sized type | +| `'a + trait`, `trait + trait` | Compound type constraint | -* `//`: line comment. -* `//!`: inner line doc comment. -* `///`: outer line doc comment. -* `/*…*/`: block comment. -* `/*!…*/`: inner block doc comment. -* `/**…*/`: outer block doc comment. +Table B-6 shows symbols that appear in the context of calling or defining +macros and specifying attributes on an item. -#### Tuples +Table B-6: Macros and Attributes -* `()`: empty tuple (*a.k.a.* unit), both literal and type. -* `(expr)`: parenthesized expression. -* `(expr,)`: single-element tuple expression. -* `(type,)`: single-element tuple type. -* `(expr, …)`: tuple expression. -* `(type, …)`: tuple type. -* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. -* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. -* `expr.0`, `expr.1`, …: tuple indexing. +| Symbol | Explanation | +|--------|-------------| +| `#[meta]` | Outer attribute | +| `#![meta]` | Inner attribute | +| `$ident` | Macro substitution | +| `$ident:kind` | Macro capture | +| `$(…)…` | Macro repetition | -#### Curly Brackets +Table B-7 shows symbols that create comments. -* `{…}`: block expression. -* `Type {…}`: `struct` literal. +Table B-7: Comments -#### Square Brackets +| Symbol | Explanation | +|--------|-------------| +| `//` | Line comment | +| `//!` | Inner line doc comment | +| `///` | Outer line doc comment | +| `/*...*/` | Block comment | +| `/*!...*/` | Inner block doc comment | +| `/**...*/` | Outer block doc comment | -* `[…]`: array literal. -* `[expr; len]`: array literal containing `len` copies of `expr`. -* `[type; len]`: array type containing `len` instances of `type`. -* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). -* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the “index”. +Table B-8 shows symbols that appear in the context of using tuples. + +Table B-8: Tuples + +| Symbol | Explanation | +|--------|-------------| +| `()` | Empty tuple (aka unit), both literal and type | +| `(expr)` | Parenthesized expression | +| `(expr,)` | Single-element tuple expression | +| `(type,)` | Single-element tuple type | +| `(expr, ...)` | Tuple expression | +| `(type, ...)` | Tuple type | +| `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants | +| `ident!(...)`, `ident!{...}`, `ident![...]` | Macro invocation | +| `expr.0`, `expr.1`, etc. | Tuple indexing | + +Table B-9 shows the contexts in which curly braces are used. + +Table B-9: Curly Brackets + +| Context | Explanation | +|---------|-------------| +| `{...}` | Block expression | +| `Type {...}` | `struct` literal | + +Table B-10 shows the contexts in which square brackets are used. + +Table B-10: Square Brackets + +| Context | Explanation | +|---------|-------------| +| `[...]` | Array literal | +| `[expr; len]` | Array literal containing `len` copies of `expr` | +| `[type; len]` | Array type containing `len` instances of `type` | +| `expr[expr]` | Collection indexing. Overloadable (`Index`, `IndexMut`) | +| `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | Collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the “index” | diff --git a/src/doc/book/2018-edition/src/appendix-03-derivable-traits.md b/src/doc/book/2018-edition/src/appendix-03-derivable-traits.md index 58daaeec47..c4b996ffdb 100644 --- a/src/doc/book/2018-edition/src/appendix-03-derivable-traits.md +++ b/src/doc/book/2018-edition/src/appendix-03-derivable-traits.md @@ -1,140 +1,104 @@ -## C - Derivable Traits +## Appendix C: Derivable Traits -In various places in the book, we’ve discussed the `derive` attribute -that you can apply to a struct or enum definition. +In various places in the book, we’ve discussed the `derive` attribute, which +you can apply to a struct or enum definition. The `derive` attribute generates +code that will implement a trait with its own default implementation on the +type you’ve annotated with the `derive` syntax. - - +In this appendix, we provide a reference of all the traits in the standard +library that you can use with `derive`. Each section covers: - - - -The `derive` attribute generates code that will implement a trait with its own -default implementation, on the type you have annotated with the `derive` -syntax. In this appendix, we provide a reference of all of the traits in the -standard library that can be used with `derive`. Each section covers: - -- What operators and methods deriving this trait will enable -- What the implementation of the trait provided by `derive` does -- What implementing the trait signifies about the type -- The conditions in which you’re allowed or not allowed to implement the trait -- Examples of operations that require the trait +* What operators and methods deriving this trait will enable +* What the implementation of the trait provided by `derive` does +* What implementing the trait signifies about the type +* The conditions in which you’re allowed or not allowed to implement the trait +* Examples of operations that require the trait If you want different behavior than that provided by the `derive` attribute, -consult the standard library documentation for each trait for details of how to +consult the standard library documentation for each trait for details on how to manually implement them. - - The rest of the traits defined in the standard library can’t be implemented on your types using `derive`. These traits don’t have sensible default behavior, so it’s up to you to implement them in the way that makes sense for what you’re trying to accomplish. An example of a trait that can’t be derived is `Display`, which handles -formatting for end users. You should always put thought into the appropriate -way to display a type to an end user: what parts of the type should an end user -be allowed to see? What parts would they find relevant? What format of the data -would be most relevant to them? The Rust compiler doesn’t have this insight and -so can’t provide appropriate default behavior for you. +formatting for end users. You should always consider the appropriate way to +display a type to an end user. What parts of the type should an end user be +allowed to see? What parts would they find relevant? What format of the data +would be most relevant to them? The Rust compiler doesn’t have this insight, so +it can’t provide appropriate default behavior for you. The list of derivable traits provided in this appendix is not comprehensive: -libraries can implement `derive` for their own traits! In this way, the list of -traits you can use `derive` with is truly open-ended. Implementing `derive` -involves using a procedural macro, which is covered in Appendix D, “Macros.” +libraries can implement `derive` for their own traits, making the list of +traits you can use `derive` with truly open-ended. Implementing `derive` +involves using a procedural macro, which is covered in Appendix D. ### `Debug` for Programmer Output -The `Debug` trait enables debug formatting in format strings, indicated by -adding `:?` within `{}` placeholders. +The `Debug` trait enables debug formatting in format strings, which you +indicate by adding `:?` within `{}` placeholders. The `Debug` trait allows you to print instances of a type for debugging purposes, so you and other programmers using your type can inspect an instance at a particular point in a program’s execution. -`Debug` is required, for example, in use of the `assert_eq!` macro, which -prints the values of instances given as arguments if the equality assertion -fails so programmers can see why the two instances weren’t equal. +The `Debug` trait is required, for example, in use of the `assert_eq!` macro. +This macro prints the values of instances given as arguments if the equality +assertion fails so programmers can see why the two instances weren’t equal. ### `PartialEq` and `Eq` for Equality Comparisons - - - The `PartialEq` trait allows you to compare instances of a type to check for -equality, and enables use of the `==` and `!=` operators. +equality and enables use of the `==` and `!=` operators. Deriving `PartialEq` implements the `eq` method. When `PartialEq` is derived on -structs, two instances are equal only if *all* fields are equal, and not equal -if any fields are not equal. When derived on enums, each variant is equal to -itself and not equal to the other variants. +structs, two instances are equal only if *all* fields are equal, and the +instances are not equal if any fields are not equal. When derived on enums, +each variant is equal to itself and not equal to the other variants. -`PartialEq` is required, for example, with the use of the `assert_eq!` macro, -which needs to be able to compare two instances of a type for equality. +The `PartialEq` trait is required, for example, with the use of the +`assert_eq!` macro, which needs to be able to compare two instances of a type +for equality. The `Eq` trait has no methods. Its purpose is to signal that for every value of the annotated type, the value is equal to itself. The `Eq` trait can only be -applied to types that also implement `PartialEq`, though not all types that +applied to types that also implement `PartialEq`, although not all types that implement `PartialEq` can implement `Eq`. One example of this is floating point -number types: the implementation of floating point numbers says that two -instances of the not-a-number value, `NaN`, are not equal to each other. +number types: the implementation of floating point numbers states that two +instances of the not-a-number (`NaN`) value are not equal to each other. -An example of when `Eq` is required is for keys in a `HashMap` so that the -`HashMap` can tell whether two keys are the same. +An example of when `Eq` is required is for keys in a `HashMap` so the +`HashMap` can tell whether two keys are the same. ### `PartialOrd` and `Ord` for Ordering Comparisons The `PartialOrd` trait allows you to compare instances of a type for sorting -purposes. A type that implements `PartialOrd` may be used with the `<`, `>`, -`<=`, and `>=` operators. The `PartialOrd` trait can only be applied to types +purposes. A type that implements `PartialOrd` can be used with the `<`, `>`, +`<=`, and `>=` operators. You can only apply the `PartialOrd` trait to types that also implement `PartialEq`. Deriving `PartialOrd` implements the `partial_cmp` method, which returns an -`Option` that will be `None` when the values given do not produce an +`Option` that will be `None` when the values given don’t produce an ordering. An example of a value that doesn’t produce an ordering, even though most values of that type can be compared, is the not-a-number (`NaN`) floating point value. Calling `partial_cmp` with any floating point number and the `NaN` floating point value will return `None`. - - - When derived on structs, `PartialOrd` compares two instances by comparing the value in each field in the order in which the fields appear in the struct definition. When derived on enums, variants of the enum declared earlier in the -enum definition are considered greater than the variants listed later. +enum definition are considered less than the variants listed later. -`PartialOrd` is required, for example, for the `gen_range` method from the -`rand` crate that generates a random value in the range specified by a low -value and a high value. +The `PartialOrd` trait is required, for example, for the `gen_range` method +from the `rand` crate that generates a random value in the range specified by a +low value and a high value. The `Ord` trait allows you to know that for any two values of the annotated type, a valid ordering will exist. The `Ord` trait implements the `cmp` method, which returns an `Ordering` rather than an `Option` because a valid -ordering will always be possible. The `Ord` trait can only be applied to types +ordering will always be possible. You can only apply the `Ord` trait to types that also implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When derived on structs and enums, `cmp` behaves the same way as the derived implementation for `partial_cmp` does with `PartialOrd`. @@ -144,22 +108,14 @@ a data structure that stores data based on the sort order of the values. ### `Clone` and `Copy` for Duplicating Values - - - The `Clone` trait allows you to explicitly create a deep copy of a value, and the duplication process might involve running arbitrary code and copying heap data. See the “Ways Variables and Data Interact: Clone” section in Chapter 4 for more information on `Clone`. -Deriving `Clone` implements the `clone` method which, when implemented for the -whole type, calls `clone` on each of the parts of the type. This means all of -the fields or values in the type must also implement `Clone` to derive `Clone`. +Deriving `Clone` implements the `clone` method, which when implemented for the +whole type, calls `clone` on each of the parts of the type. This means all the +fields or values in the type must also implement `Clone` to derive `Clone`. An example of when `Clone` is required is when calling the `to_vec` method on a slice. The slice doesn’t own the type instances it contains, but the vector @@ -170,61 +126,49 @@ The `Copy` trait allows you to duplicate a value by only copying bits stored on the stack; no arbitrary code is necessary. See the “Stack-Only Data: Copy” section in Chapter 4 for more information on `Copy`. - - - -The `Copy` trait does not define any methods to prevent programmers from -overloading those methods violating the assumption that no arbitrary code is -being run. That way, all programmers can assume that copying a value will be +The `Copy` trait doesn’t define any methods to prevent programmers from +overloading those methods and violating the assumption that no arbitrary code +is being run. That way, all programmers can assume that copying a value will be very fast. - - +You can derive `Copy` on any type whose parts all implement `Copy`. You can +only apply the `Copy` trait to types that also implement `Clone`, because a +type that implements `Copy` has a trivial implementation of `Clone` that +performs the same task as `Copy`. -You can derive `Copy` on any type whose parts all implement `Copy`. The `Copy` -trait can only be applied to types that also implement `Clone`, as a type that -implements `Copy` has a trivial implementation of `Clone`, doing the same thing -as `Copy`. +The `Copy` trait is rarely required; types that implement `Copy` have +optimizations available, meaning you don’t have to call `clone`, which makes +the code more concise. -`Copy` is rarely required; types implement `Copy` have optimizations available -mean you don’t have to call `clone`, making the code more concise. - - - - -Everything possible with `Copy` can also be accomplished with `Clone`, but the +Everything possible with `Copy` you can also accomplish with `Clone`, but the code might be slower or have to use `clone` in places. ### `Hash` for Mapping a Value to a Value of Fixed Size The `Hash` trait allows you to take an instance of a type of arbitrary size and -map that instance to a value of fixed size, using a hash function. Deriving +map that instance to a value of fixed size using a hash function. Deriving `Hash` implements the `hash` method. The derived implementation of the `hash` method combines the result of calling `hash` on each of the parts of the type, meaning all fields or values must also implement `Hash` to derive `Hash`. -An example of when `Hash` is required is in storing keys in a `HashMap`, in -order to store data efficiently. +An example of when `Hash` is required is in storing keys in a `HashMap` +to store data efficiently. ### `Default` for Default Values The `Default` trait allows you to create a default value for a type. Deriving -`Default` implements the `default` method. The derived implementation of the -`default` method calls the `default` method on each part of the type, meaning -all fields or values in the type must also implement `Default` to derive -`Default.` +`Default` implements the `default` function. The derived implementation of the +`default` function calls the `default` function on each part of the type, +meaning all fields or values in the type must also implement `Default` to +derive `Default.` -`Default::default` is commonly used in combination with the struct update -syntax discussed in the “Creating Instances From Other Instances With Struct -Update Syntax” section in Chapter 5. You can customize a few fields of a struct -and then set and use a default value for the rest of the fields by using +The `Default::default` function is commonly used in combination with the struct +update syntax discussed in the “Creating Instances From Other Instances With +Struct Update Syntax” section in Chapter 5. You can customize a few fields of a +struct and then set and use a default value for the rest of the fields by using `..Default::default()`. -`Default` is required when, for example, you use the `unwrap_or_default` method -on `Option` instances. If the `Option` is `None`, the `unwrap_or_default` -method will return the result of `Default::default` for the type `T` stored in -the `Option`. +The `Default` trait is required when you use the method `unwrap_or_default` on +`Option` instances, for example. If the `Option` is `None`, the method +`unwrap_or_default` will return the result of `Default::default` for the type +`T` stored in the `Option`. diff --git a/src/doc/book/2018-edition/src/appendix-04-macros.md b/src/doc/book/2018-edition/src/appendix-04-macros.md index 5f8bfbff88..0f9d2d4e75 100644 --- a/src/doc/book/2018-edition/src/appendix-04-macros.md +++ b/src/doc/book/2018-edition/src/appendix-04-macros.md @@ -1,53 +1,55 @@ ## Appendix D: Macros -We’ve used macros like `println!` throughout this book, but haven’t fully -explored what a macro is and how it works. This appendix will explain: +We’ve used macros like `println!` throughout this book but haven’t fully +explored what a macro is and how it works. This appendix explains macros as +follows: -- What macros are and how they differ from functions -- How to define a declarative macro to do metaprogramming -- How to define a procedural macro to create custom `derive` traits +* What macros are and how they differ from functions +* How to define a declarative macro to do metaprogramming +* How to define a procedural macro to create custom `derive` traits We’re covering the details of macros in an appendix because they’re still evolving in Rust. Macros have changed and, in the near future, will change at a quicker rate than the rest of the language and standard library since Rust 1.0, -so this section is more likely to date than the rest of the book. The code -shown here will still continue to work with future versions, due to Rust’s -stability guarantees, but there may be additional capabilities or easier ways +so this section is more likely to become out-of-date than the rest of the book. +Due to Rust’s stability guarantees, the code shown here will continue to work +with future versions, but there may be additional capabilities or easier ways to write macros that weren’t available at the time of this publication. Bear -that in mind if you try to implement anything from this appendix. +that in mind when you try to implement anything from this appendix. ### The Difference Between Macros and Functions -Fundamentally, macros are a way of writing code that writes other code, known -as *metaprogramming*. In Appendix C, we discussed the `derive` attribute, which -generates an implementation of various traits for you. We’ve also used the -`println!` and `vec!` macros throughout the book. All of these macros *expand* -to produce more code than the code you’ve written yourself. +Fundamentally, macros are a way of writing code that writes other code, which +is known as *metaprogramming*. In Appendix C, we discussed the `derive` +attribute, which generates an implementation of various traits for you. We’ve +also used the `println!` and `vec!` macros throughout the book. All of these +macros *expand* to produce more code than the code you’ve written manually. Metaprogramming is useful for reducing the amount of code you have to write and maintain, which is also one of the roles of functions. However, macros have some additional powers that functions don’t have. -A function signature has to declare the number and type of parameters the +A function signature must declare the number and type of parameters the function has. Macros, on the other hand, can take a variable number of -parameters: we can call `println!("hello")` with one argument, or +parameters: we can call `println!("hello")` with one argument or `println!("hello {}", name)` with two arguments. Also, macros are expanded before the compiler interprets the meaning of the code, so a macro can, for example, implement a trait on a given type. A function can’t, because it gets called at runtime and a trait needs to be implemented at compile time. -The downside to implementing a macro over a function is that macro definitions -are more complex than function definitions because you’re writing Rust code -that writes Rust code. Due to this indirection, macro definitions are generally -more difficult to read, understand, and maintain than function definitions. +The downside to implementing a macro instead of a function is that macro +definitions are more complex than function definitions because you’re writing +Rust code that writes Rust code. Due to this indirection, macro definitions are +generally more difficult to read, understand, and maintain than function +definitions. Another difference between macros and functions is that macro definitions -aren’t namespaced within modules like function definitions are. In order to -prevent unexpected name clashes when using external crates, you have to -explicitly bring the macros into the scope of your project at the same time as -bringing the external crate into scope, using the `#[macro_use]` annotation. -The following example would bring all the macros defined in the `serde` crate -into the scope of the current crate: +aren’t namespaced within modules like function definitions are. To prevent +unexpected name clashes when using external crates, you have to explicitly +bring the macros into the scope of your project at the same time as you bring +the external crate into scope, using the `#[macro_use]` annotation. The +following example would bring all the macros defined in the `serde` crate into +the scope of the current crate: ```rust,ignore #[macro_use] @@ -56,12 +58,12 @@ extern crate serde; If `extern crate` was able to bring macros into scope by default without this explicit annotation, you would be prevented from using two crates that happened -to define macros with the same name. In practice this conflict doesn’t come up -much, but the more crates you use, the more likely it is. +to define macros with the same name. In practice, this conflict doesn’t occur +often, but the more crates you use, the more likely it is. -One last important difference between macros and functions: macros must be -defined or brought into scope *before* they’re called in a file, whereas -functions can be defined anywhere and called anywhere. +There is one last important difference between macros and functions: you must +define or bring macros into scope *before* you call them in a file, whereas you +can define functions anywhere and call them anywhere. ### Declarative Macros with `macro_rules!` for General Metaprogramming @@ -72,15 +74,15 @@ something similar to a Rust `match` expression. As discussed in Chapter 6, `match` expressions are control structures that take an expression, compare the resulting value of the expression to patterns, and then run the code associated with the matching pattern. Macros also compare a value to patterns that have -code associated with them, but in this case the value is the literal Rust +code associated with them; in this situation, the value is the literal Rust source code passed to the macro, the patterns are compared with the structure of that source code, and the code associated with each pattern is the code that replaces the code passed to the macro. This all happens during compilation. To define a macro, you use the `macro_rules!` construct. Let’s explore how to -use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter -8 covered how we can use the `vec!` macro to create a new vector with -particular values. For example, this macro creates a new vector with three +use `macro_rules!` by looking at how the `vec!` macro is defined. Chapter 8 +covered how we can use the `vec!` macro to create a new vector with particular +values. For example, the following macro creates a new vector with three integers inside: ```rust @@ -88,11 +90,11 @@ let v: Vec = vec![1, 2, 3]; ``` We could also use the `vec!` macro to make a vector of two integers or a vector -of five string slices---we wouldn’t be able to use a function to do the same +of five string slices. We wouldn’t be able to use a function to do the same because we wouldn’t know the number or type of values up front. -Let’s take a look at a slightly simplified definition of the `vec!` macro in -Listing AD-1: +Let’s look at a slightly simplified definition of the `vec!` macro in Listing +D-1. ```rust #[macro_export] @@ -109,33 +111,33 @@ macro_rules! vec { } ``` -Listing AD-1: A simplified version of the `vec!` macro definition +Listing D-1: A simplified version of the `vec!` macro +definition -> Note: the actual definition of the `vec!` macro in the standard library -> includes code to pre-allocate the correct amount of memory up-front. That -> code is an optimization that we’ve chosen not to include here to make the -> example simpler. +> Note: The actual definition of the `vec!` macro in the standard library +> includes code to preallocate the correct amount of memory up front. That code +> is an optimization that we don’t include here to make the example simpler. The `#[macro_export]` annotation indicates that this macro should be made available whenever the crate in which we’re defining the macro is imported. Without this annotation, even if someone depending on this crate uses the -`#[macro_use]` annotation, the macro would not be brought into scope. +`#[macro_use]` annotation, the macro wouldn’t be brought into scope. We then start the macro definition with `macro_rules!` and the name of the -macro we’re defining *without* the exclamation mark. The name---in this case -`vec`---is followed by curly brackets denoting the body of the macro definition. +macro we’re defining *without* the exclamation mark. The name, in this case +`vec`, is followed by curly brackets denoting the body of the macro definition. The structure in the `vec!` body is similar to the structure of a `match` expression. Here we have one arm with the pattern `( $( $x:expr ),* )`, followed by `=>` and the block of code associated with this pattern. If the pattern matches, the associated block of code will be emitted. Given that this -is the only pattern in this macro, there’s only one valid way to match; any +is the only pattern in this macro, there is only one valid way to match; any other will be an error. More complex macros will have more than one arm. Valid pattern syntax in macro definitions is different than the pattern syntax covered in Chapter 18 because macro patterns are matched against Rust code structure rather than values. Let’s walk through what the pieces of the pattern -in Listing AD-1 mean; for the full macro pattern syntax, see [the reference]. +in Listing D-1 mean; for the full macro pattern syntax, see [the reference]. [the reference]: ../../reference/macros.html @@ -154,16 +156,11 @@ When we call this macro with `vec![1, 2, 3];`, the `$x` pattern matches three times with the three expressions `1`, `2`, and `3`. Now let’s look at the pattern in the body of the code associated with this arm: -The `temp_vec.push()` code within the `$()*` part is generated for each part +the `temp_vec.push()` code within the `$()*` part is generated for each part that matches `$()` in the pattern, zero or more times depending on how many times the pattern matches. The `$x` is replaced with each expression matched. When we call this macro with `vec![1, 2, 3];`, the code generated that replaces -this macro call will be: - - - +this macro call will be the following: ```rust,ignore let mut temp_vec = Vec::new(); @@ -176,10 +173,10 @@ temp_vec We’ve defined a macro that can take any number of arguments of any type and can generate code to create a vector containing the specified elements. -Given that most Rust programmers will *use* macros more than *write* macros, -that’s all we’ll discuss about `macro_rules!` in this book. To learn more about -how to write macros, consult the online documentation or other resources such -as [The Little Book of Rust Macros][tlborm]. +Given that most Rust programmers will *use* macros more than *write* macros, we +won’t discuss `macro_rules!` any further. To learn more about how to write +macros, consult the online documentation or other resources, such as [“The +Little Book of Rust Macros”][tlborm]. [tlborm]: https://danielkeep.github.io/tlborm/book/index.html @@ -188,22 +185,20 @@ as [The Little Book of Rust Macros][tlborm]. The second form of macros is called *procedural macros* because they’re more like functions (which are a type of procedure). Procedural macros accept some Rust code as an input, operate on that code, and produce some Rust code as an -output, rather than matching against patterns and replacing the code with other -code as declarative macros do. At the time of writing, you can only really -define procedural macros to allow your traits to be implemented on a type by +output rather than matching against patterns and replacing the code with other +code as declarative macros do. At the time of this writing, you can only define +procedural macros to allow your traits to be implemented on a type by specifying the trait name in a `derive` annotation. -We’re going to create a crate named `hello_macro` that defines a trait named +We’ll create a crate named `hello_macro` that defines a trait named `HelloMacro` with one associated function named `hello_macro`. Rather than -making users of our crate implement the `HelloMacro` trait for each of their +making our crate users implement the `HelloMacro` trait for each of their types, we’ll provide a procedural macro so users can annotate their type with `#[derive(HelloMacro)]` to get a default implementation of the `hello_macro` function. The default implementation will print `Hello, Macro! My name is TypeName!` where `TypeName` is the name of the type on which this trait has -been defined. - -In other words, we’re going to write a crate that enables another programmer to -write code like Listing AD-2 using our crate: +been defined. In other words, we’ll write a crate that enables another +programmer to write code like Listing D-2 using our crate. Filename: src/main.rs @@ -222,17 +217,17 @@ fn main() { } ``` -Listing AD-2: The code a user of our crate will be able -to write with use of our procedural macro +Listing D-2: The code a user of our crate will be able to +write when using our procedural macro -This code will print `Hello, Macro! My name is Pancakes!` when we’re done. Let’s -get started! First we need to make a new library crate: +This code will print `Hello, Macro! My name is Pancakes!` when we’re done. The +first step is to make a new library crate, like this: ```text $ cargo new hello_macro --lib ``` -Now we’ll define the `HelloMacro` trait and its associated function: +Next, we’ll define the `HelloMacro` trait and its associated function: Filename: src/lib.rs @@ -242,9 +237,8 @@ pub trait HelloMacro { } ``` -We have a trait and its function. At this point, a user of our crate would be -able to implement the trait themselves to achieve the desired functionality, -like so: +We have a trait and its function. At this point, our crate user could implement +the trait to achieve the desired functionality, like so: ```rust,ignore extern crate hello_macro; @@ -264,24 +258,21 @@ fn main() { } ``` -However, they would need to write out the implementation block for each type -they wanted to use with `hello_macro`; we’d like to save them this work. +However, they would need to write the implementation block for each type they +wanted to use with `hello_macro`; we want to spare them from having to do this +work. Additionally, we can’t yet provide a default implementation for the -`hello_macro` function that will print out the name of the type the trait is -implemented on: Rust doesn’t have reflection capabilities, so can’t look up the -type’s name at runtime. We need a macro to generate code at compile time. +`hello_macro` function that will print the name of the type the trait is +implemented on: Rust doesn’t have reflection capabilities, so it can’t look up +the type’s name at runtime. We need a macro to generate code at compile time. - - - -The next step is to define the procedural macro. At the time of writing, +The next step is to define the procedural macro. At the time of this writing, procedural macros need to be in their own crate. Eventually, this restriction -may be lifted. The convention for structuring crates and macro crates is as -such: for a crate named `foo`, a custom derive procedural macro crate is called -`foo-derive`. Let’s start a new crate called `hello_macro_derive` inside our -`hello_macro` project: +might be lifted. The convention for structuring crates and macro crates is as +follows: for a crate named `foo`, a custom derive procedural macro crate is +called `foo_derive`. Let’s start a new crate called `hello_macro_derive` inside +our `hello_macro` project: ```text $ cargo new hello_macro_derive --lib @@ -291,15 +282,15 @@ Our two crates are tightly related, so we create the procedural macro crate within the directory of our `hello_macro` crate. If we change the trait definition in `hello_macro`, we’ll have to change the implementation of the procedural macro in `hello_macro_derive` as well. The two crates will need to -be published separately, though, and programmers using these crates will need -to add both as dependencies and bring them both into scope. We could instead -have the `hello_macro` crate use `hello_macro_derive` as a dependency and -re-export the procedural macro code, but the way we’ve structured the project -makes it possible for programmers to use `hello_macro` even if they don’t want -the `derive` functionality. +be published separately, and programmers using these crates will need to add +both as dependencies and bring them both into scope. We could instead have the +`hello_macro` crate use `hello_macro_derive` as a dependency and reexport the +procedural macro code. But the way we’ve structured the project makes it +possible for programmers to use `hello_macro` even if they don’t want the +`derive` functionality. We need to declare the `hello_macro_derive` crate as a procedural macro crate. -We’ll also need functionality from the `syn` and `quote` crates, as we’ll see +We’ll also need functionality from the `syn` and `quote` crates, as you’ll see in a moment, so we need to add them as dependencies. Add the following to the *Cargo.toml* file for `hello_macro_derive`: @@ -314,16 +305,10 @@ syn = "0.11.11" quote = "0.3.15" ``` -To start defining the procedural macro, place the code from Listing AD-3 in -your *src/lib.rs* for the `hello_macro_derive` crate. Note that this won’t +To start defining the procedural macro, place the code in Listing D-3 into your +*src/lib.rs* file for the `hello_macro_derive` crate. Note that this code won’t compile until we add a definition for the `impl_hello_macro` function. -Note the way we’ve split the functions in AD-3; this will be the same for -almost every procedural macro crate you see or create, as it makes writing a -procedural macro more convenient. What you choose to do in the place where the -`impl_hello_macro` function is called will be different depending on the -purpose of your procedural macro. - Filename: hello_macro_derive/src/lib.rs ```rust,ignore @@ -350,10 +335,16 @@ pub fn hello_macro_derive(input: TokenStream) -> TokenStream { } ``` -Listing AD-3: Code that most procedural macro crates will +Listing D-3: Code that most procedural macro crates will need to have for processing Rust code -We have introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The +Notice the way we’ve split the functions in D-3; this will be the same for +almost every procedural macro crate you see or create, because it makes writing +a procedural macro more convenient. What you choose to do in the place where +the `impl_hello_macro` function is called will be different depending on your +procedural macro’s purpose. + +We’ve introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The `proc_macro` crate comes with Rust, so we didn’t need to add that to the dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust code into a string containing that Rust code. The `syn` crate parses Rust code @@ -366,29 +357,24 @@ to handle: writing a full parser for Rust code is no simple task. [`quote`]: https://crates.io/crates/quote The `hello_macro_derive` function will get called when a user of our library -specifies `#[derive(HelloMacro)]` on a type, because we’ve annotated the -`hello_macro_derive` function here with `proc_macro_derive` and specified the -name, `HelloMacro`, which matches our trait name; that’s the convention most -procedural macros follow. +specifies `#[derive(HelloMacro)]` on a type. The reason is that we’ve annotated +the `hello_macro_derive` function here with `proc_macro_derive` and specified +the name, `HelloMacro`, which matches our trait name; that’s the convention +most procedural macros follow. This function first converts the `input` from a `TokenStream` to a `String` by calling `to_string`. This `String` is a string representation of the Rust code -for which we are deriving `HelloMacro`. In the example in Listing AD-2, `s` -will have the `String` value `struct Pancakes;` because that’s the Rust code we +for which we are deriving `HelloMacro`. In the example in Listing D-2, `s` will +have the `String` value `struct Pancakes;` because that is the Rust code we added the `#[derive(HelloMacro)]` annotation to. - - +> Note: At the time of this writing, you can only convert a `TokenStream` to a +> string. A richer API will exist in the future. -> Note: At the time of writing, the only thing you can do with a `TokenStream` -> is convert it to a string. A richer API will exist in the future. - -Now we need to be able to parse the Rust code `String` into a data structure -that we can then interpret and perform operations on. This is where `syn` comes -to play. The `parse_derive_input` function in `syn` takes a `String` and -returns a `DeriveInput` struct representing the parsed Rust code. The following +Now we need to parse the Rust code `String` into a data structure that we can +then interpret and perform operations on. This is where `syn` comes into play. +The `parse_derive_input` function in `syn` takes a `String` and returns a +`DeriveInput` struct representing the parsed Rust code. The following code shows the relevant parts of the `DeriveInput` struct we get from parsing the string `struct Pancakes;`: @@ -408,29 +394,29 @@ DeriveInput { The fields of this struct show that the Rust code we’ve parsed is a unit struct with the `ident` (identifier, meaning the name) of `Pancakes`. There are more fields on this struct for describing all sorts of Rust code; check the [`syn` -API docs for `DeriveInput`][syn-docs] for more information. +documentation for `DeriveInput`][syn-docs] for more information. [syn-docs]: https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html -At this point we haven’t defined the `impl_hello_macro` function, which is -where we’ll build the new Rust code we want to include. Before we get to that, -the last part of this `hello_macro_derive` function is using the `parse` +At this point, we haven’t defined the `impl_hello_macro` function, which is +where we’ll build the new Rust code we want to include. But before we do, note +that the last part of this `hello_macro_derive` function uses the `parse` function from the `quote` crate to turn the output of the `impl_hello_macro` function back into a `TokenStream`. The returned `TokenStream` is added to the -code that users of our crate write so that when they compile their crate, they -get extra functionality we provide. +code that our crate users write, so when they compile their crate, they’ll get +extra functionality that we provide. -You may have noticed that we’re calling `unwrap` to panic if the calls to the +You might have noticed that we’re calling `unwrap` to panic if the calls to the `parse_derive_input` or `parse` functions fail here. Panicking on errors is necessary in procedural macro code because `proc_macro_derive` functions must -return `TokenStream` rather than `Result` in order to conform to the procedural -macro API. We’ve chosen to keep this example simple by using `unwrap`; in -production code you should provide more specific error messages about what went -wrong by using `expect` or `panic!`. +return `TokenStream` rather than `Result` to conform to the procedural macro +API. We’ve chosen to simplify this example by using `unwrap`; in production +code, you should provide more specific error messages about what went wrong by +using `panic!` or `expect`. Now that we have the code to turn the annotated Rust code from a `TokenStream` -into a `String` and a `DeriveInput` instance, let’s generate the code -implementing the `HelloMacro` trait on the annotated type: +into a `String` and a `DeriveInput` instance, let’s generate the code that +implements the `HelloMacro` trait on the annotated type: Filename: hello_macro_derive/src/lib.rs @@ -448,12 +434,12 @@ fn impl_hello_macro(ast: &syn::DeriveInput) -> quote::Tokens { ``` We get an `Ident` struct instance containing the name (identifier) of the -annotated type using `ast.ident`. With the code from Listing AD-2, `name` will -be `Ident("Pancakes")`. +annotated type using `ast.ident`. The code in Listing D-2 specifies that the +`name` will be `Ident("Pancakes")`. -The `quote!` macro lets us write up the Rust code that we want to return and -convert it into `quote::Tokens`. This macro also provides some really cool -templating mechanics; we can write `#name` and `quote!` will replace it with +The `quote!` macro lets us write the Rust code that we want to return and +convert it into `quote::Tokens`. This macro also provides some very cool +templating mechanics; we can write `#name`, and `quote!` will replace it with the value in the variable named `name`. You can even do some repetition similar to the way regular macros work. Check out [the `quote` crate’s docs][quote-docs] for a thorough introduction. @@ -470,18 +456,18 @@ The `stringify!` macro used here is built into Rust. It takes a Rust expression, such as `1 + 2`, and at compile time turns the expression into a string literal, such as `"1 + 2"`. This is different than `format!` or `println!`, which evaluate the expression and then turn the result into a -`String`. There’s a possibility that the `#name` input might be an expression -to print out literally so we use `stringify!`. Using `stringify!` also saves an +`String`. There is a possibility that the `#name` input might be an expression +to print literally, so we use `stringify!`. Using `stringify!` also saves an allocation by converting `#name` to a string literal at compile time. At this point, `cargo build` should complete successfully in both `hello_macro` -and `hello_macro_derive`. Let’s hook these crates up to the code in Listing -AD-2 to see it in action! Create a new binary project in your `projects` -directory with `cargo new --bin pancakes`. We need to add both `hello_macro` -and `hello_macro_derive` as dependencies in the `pancakes` crate’s -*Cargo.toml*. If you’ve chosen to publish your versions of `hello_macro` and -`hello_macro_derive` to *https://crates.io* they would be regular dependencies; -if not, you can specify them as `path` dependencies as follows: +and `hello_macro_derive`. Let’s hook up these crates to the code in Listing D-2 +to see the procedural macro in action! Create a new binary project in your +*projects* directory using `cargo new pancakes`. We need to add +`hello_macro` and `hello_macro_derive` as dependencies in the `pancakes` +crate’s *Cargo.toml*. If you’re publishing your versions of `hello_macro` and +`hello_macro_derive` to *https://crates.io/*, they would be regular +dependencies; if not, you can specify them as `path` dependencies as follows: ```toml [dependencies] @@ -489,16 +475,16 @@ hello_macro = { path = "../hello_macro" } hello_macro_derive = { path = "../hello_macro/hello_macro_derive" } ``` -Put the code from Listing AD-2 into *src/main.rs*, and when you run `cargo run` -it should print `Hello, Macro! My name is Pancakes!` The implementation of the +Put the code from Listing D-2 into *src/main.rs*, and run `cargo run`: it +should print `Hello, Macro! My name is Pancakes!` The implementation of the `HelloMacro` trait from the procedural macro was included without the -`pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` took care -of adding the trait implementation. +`pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` added the +trait implementation. ### The Future of Macros -In the future, we’ll be expanding both declarative and procedural macros. Rust -will use better declarative macro system with the `macro` keyword, and we’ll -add more types of procedural macros, for more powerful tasks than just -`derive`. These systems are still under development at the time of publication; +In the future, Rust will expand declarative and procedural macros. Rust will +use a better declarative macro system with the `macro` keyword and will add +more types of procedural macros for more powerful tasks than just `derive`. +These systems are still under development at the time of this publication; please consult the online Rust documentation for the latest information. diff --git a/src/doc/book/2018-edition/src/appendix-05-translation.md b/src/doc/book/2018-edition/src/appendix-05-translation.md index a3e029e3c4..96abac652a 100644 --- a/src/doc/book/2018-edition/src/appendix-05-translation.md +++ b/src/doc/book/2018-edition/src/appendix-05-translation.md @@ -11,7 +11,7 @@ For resources in languages other than English. Most are still in progress; see - [简体中文](http://www.broadview.com.cn/article/144), [alternate](https://github.com/KaiserY/trpl-zh-cn) - [Українська](https://github.com/pavloslav/rust-book-uk-ua) - [Español](https://github.com/thecodix/book) -- [Italiano](https://github.com/CodelessFuture/trpl2-it) +- [Italiano](https://github.com/AgeOfWar/rust-book-it) - [Русский](https://github.com/iDeBugger/rust-book-ru) - [한국어](https://github.com/rinthel/rust-lang-book-ko) - [日本語](https://github.com/hazama-yuinyan/book) diff --git a/src/doc/book/2018-edition/src/appendix-06-newest-features.md b/src/doc/book/2018-edition/src/appendix-06-newest-features.md deleted file mode 100644 index af226c896f..0000000000 --- a/src/doc/book/2018-edition/src/appendix-06-newest-features.md +++ /dev/null @@ -1,128 +0,0 @@ -# Appendix F - Newest Features - -This appendix documents features that have been added to stable Rust since the -main part of the book was completed. - - -## Field init shorthand - -We can initialize a data structure (struct, enum, union) with named -fields, by writing `fieldname` as a shorthand for `fieldname: fieldname`. -This allows a compact syntax for initialization, with less duplication: - -```rust -#[derive(Debug)] -struct Person { - name: String, - age: u8, -} - -fn main() { - let name = String::from("Peter"); - let age = 27; - - // Using full syntax: - let peter = Person { name: name, age: age }; - - let name = String::from("Portia"); - let age = 27; - - // Using field init shorthand: - let portia = Person { name, age }; - - println!("{:?}", portia); -} -``` - - -## Returning from loops - -One of the uses of a `loop` is to retry an operation you know can fail, such as -checking if a thread completed its job. However, you might need to pass the -result of that operation to the rest of your code. If you add it to the `break` -expression you use to stop the loop, it will be returned by the broken loop: - -```rust -fn main() { - let mut counter = 0; - - let result = loop { - counter += 1; - - if counter == 10 { - break counter * 2; - } - }; - - assert_eq!(result, 20); -} -``` - -## Nested groups in `use` declarations - -If you have a complex module tree with many different submodules and you need -to import a few items from each one, it might be useful to group all the -imports in the same declaration to keep your code clean and avoid repeating the -base modules’ name. - -The `use` declaration supports nesting to help you in those cases, both with -simple imports and glob ones. For example this snippets imports `bar`, `Foo`, -all the items in `baz` and `Bar`: - -```rust -# #![allow(unused_imports, dead_code)] -# -# mod foo { -# pub mod bar { -# pub type Foo = (); -# } -# pub mod baz { -# pub mod quux { -# pub type Bar = (); -# } -# } -# } -# -use foo::{ - bar::{self, Foo}, - baz::{*, quux::Bar}, -}; -# -# fn main() {} -``` - -## Inclusive ranges - -Previously, when a range (`..` or `...`) was used as an expression, it had to be -`..`, which is exclusive of the upper bound, while patterns had to use `...`, -which is inclusive of the upper bound. Now, `..=` is accepted as syntax for -inclusive ranges in both expression and range context: - -```rust -fn main() { - for i in 0 ..= 10 { - match i { - 0 ..= 5 => println!("{}: low", i), - 6 ..= 10 => println!("{}: high", i), - _ => println!("{}: out of range", i), - } - } -} -``` - -The `...` syntax is still accepted in matches, but it is not accepted in -expressions. `..=` should be preferred. - -## 128-bit integers - -Rust 1.26.0 added 128-bit integer primitives: - -- `u128`: A 128-bit unsigned integer with range [0, 2^128 - 1] -- `i128`: A 128-bit signed integer with range [-(2^127), 2^127 - 1] - -These primitives are implemented efficiently via LLVM support. They are -available even on platforms that don’t natively support 128-bit integers and -can be used like the other integer types. - -These primitives can be very useful for algorithms that need to use very large -integers efficiently, such as certain cryptographic algorithms. diff --git a/src/doc/book/2018-edition/src/appendix-07-nightly-rust.md b/src/doc/book/2018-edition/src/appendix-06-nightly-rust.md similarity index 96% rename from src/doc/book/2018-edition/src/appendix-07-nightly-rust.md rename to src/doc/book/2018-edition/src/appendix-06-nightly-rust.md index 4b71ecd284..d276d9ec35 100644 --- a/src/doc/book/2018-edition/src/appendix-07-nightly-rust.md +++ b/src/doc/book/2018-edition/src/appendix-06-nightly-rust.md @@ -1,10 +1,7 @@ -# Appendix G - How Rust is Made and “Nightly Rust” +# Appendix F - How Rust is Made and “Nightly Rust” This appendix is about how Rust is made and how that affects you as a Rust -developer. We mentioned that the output in this book was generated by stable -Rust 1.21.0, but any examples that compile should continue to compile in any -stable version of Rust greater than that. This section is to explain how we -ensure this is true! +developer. ### Stability Without Stagnation @@ -150,7 +147,7 @@ $ rustup install nightly You can see all of the *toolchains* (releases of Rust and associated components) you have installed with `rustup` as well. Here’s an example on one -of your authors’ computers: +of your authors’ Windows computer: ```powershell > rustup toolchain list diff --git a/src/doc/book/2018-edition/src/ch00-00-introduction.md b/src/doc/book/2018-edition/src/ch00-00-introduction.md index 1e917ed925..21db273bd6 100644 --- a/src/doc/book/2018-edition/src/ch00-00-introduction.md +++ b/src/doc/book/2018-edition/src/ch00-00-introduction.md @@ -1,7 +1,13 @@ # Introduction -Welcome to *The Rust Programming Language*, an introductory book about Rust. +> Note: This edition of the book is the same as [The Rust Programming +> Language][nsprust] available in print and ebook format from [No Starch +> Press][nsp]. +[nsprust]: https://nostarch.com/rust +[nsp]: https://nostarch.com/ + +Welcome to *The Rust Programming Language*, an introductory book about Rust. The Rust programming language helps you write faster, more reliable software. High-level ergonomics and low-level control are often at odds in programming language design; Rust challenges that conflict. Through balancing powerful @@ -18,11 +24,11 @@ the most important groups. Rust is proving to be a productive tool for collaborating among large teams of developers with varying levels of systems programming knowledge. Low-level code -is prone to a variety of subtle bugs, which in most other languages can only be -caught through extensive testing and careful code review by experienced +is prone to a variety of subtle bugs, which in most other languages can be +caught only through extensive testing and careful code review by experienced developers. In Rust, the compiler plays a gatekeeper role by refusing to compile code with these elusive bugs, including concurrency bugs. By working -alongside the compiler, the team can spend more time focusing on the program’s +alongside the compiler, the team can spend their time focusing on the program’s logic rather than chasing down bugs. Rust also brings contemporary developer tools to the systems programming world: @@ -51,7 +57,7 @@ programming. Hundreds of companies, large and small, use Rust in production for a variety of tasks. Those tasks include command line tools, web services, DevOps tooling, embedded devices, audio and video analysis and transcoding, cryptocurrencies, -bioinformatics, search engines, internet of things applications, machine +bioinformatics, search engines, Internet of Things applications, machine learning, and even major parts of the Firefox web browser. ### Open Source Developers @@ -65,18 +71,17 @@ language. Rust is for people who crave speed and stability in a language. By speed, we mean the speed of the programs that you can create with Rust and the speed at which Rust lets you write them. The Rust compiler’s checks ensure stability -through feature additions and refactoring as opposed to brittle legacy code in -languages without these checks that developers are afraid to modify. By -striving for zero-cost abstractions, higher-level features that compile to -lower-level code as fast as code written manually, Rust endeavors to make safe -code be fast code as well. +through feature additions and refactoring. This is in contrast to the brittle +legacy code in languages without these checks, which developers are often +afraid to modify. By striving for zero-cost abstractions, higher-level features +that compile to lower-level code as fast as code written manually, Rust +endeavors to make safe code be fast code as well. -Although we’ve not provided a complete list of everyone the Rust language hopes -to support, those we have mentioned are some of the biggest stakeholders. -Overall, Rust’s greatest ambition is to eliminate the dichotomy of the -trade-offs that programmers have accepted for decades: safety *and* -productivity, speed *and* ergonomics. Give Rust a try, and see if its choices -work for you. +The Rust language hopes to support many other users as well; those mentioned +here are merely some of the biggest stakeholders. Overall, Rust’s greatest +ambition is to eliminate the trade-offs that programmers have accepted for +decades by providing safety *and* productivity, speed *and* ergonomics. Give +Rust a try and see if its choices work for you. ## Who This Book Is For @@ -99,16 +104,17 @@ chapters. In concept chapters, you’ll learn about an aspect of Rust. In projec chapters, we’ll build small programs together, applying what you’ve learned so far. Chapters 2, 12, and 20 are project chapters; the rest are concept chapters. -Additionally, Chapter 2 is a hands-on introduction to the Rust language. We’ll -cover concepts at a high level, and later chapters will provide additional -detail. If you want to get your hands dirty right away, Chapter 2 is the one -for that. At first, you might even want to skip Chapter 3, which covers Rust -features similar to other programming language features, and head straight to -Chapter 4 to learn about Rust’s ownership system. However, if you’re a -particularly meticulous learner who prefers to learn every detail before moving -onto the next, you might want to skip Chapter 2 and go straight to Chapter 3, -returning to Chapter 2 when you’d like to work on a project applying those -details. +Chapter 1 explains how to install Rust, how to write a Hello, world! program, +and how to use Cargo, Rust’s package manager and build tool. Chapter 2 is a +hands-on introduction to the Rust language. Here we cover concepts at a high +level, and later chapters will provide additional detail. If you want to get +your hands dirty right away, Chapter 2 is the place for that. At first, you +might even want to skip Chapter 3, which covers Rust features similar to those +of other programming languages, and head straight to Chapter 4 to learn about +Rust’s ownership system. However, if you’re a particularly meticulous learner +who prefers to learn every detail before moving on to the next, you might want +to skip Chapter 2 and go straight to Chapter 3, returning to Chapter 2 when +you’d like to work on a project applying the details you’ve learned. Chapter 5 discusses structs and methods, and Chapter 6 covers enums, `match` expressions, and the `if let` control flow construct. You’ll use structs and @@ -118,15 +124,15 @@ In Chapter 7, you’ll learn about Rust’s module system and about privacy rule for organizing your code and its public Application Programming Interface (API). Chapter 8 discusses some common collection data structures that the standard library provides, such as vectors, strings, and hash maps. Chapter 9 -explores Rust’s error handling philosophy and techniques. +explores Rust’s error-handling philosophy and techniques. Chapter 10 digs into generics, traits, and lifetimes, which give you the power to define code that applies to multiple types. Chapter 11 is all about testing, -which is still necessary even with Rust’s safety guarantees to ensure your -program’s logic is correct. In Chapter 12, we’ll build our own implementation -of a subset of functionality from the `grep` command line tool that searches -for text within files. For this, we’ll use many of the concepts we discussed in -the previous chapters. +which even with Rust’s safety guarantees is necessary to ensure your program’s +logic is correct. In Chapter 12, we’ll build our own implementation of a subset +of functionality from the `grep` command line tool that searches for text +within files. For this, we’ll use many of the concepts we discussed in the +previous chapters. Chapter 13 explores closures and iterators: features of Rust that come from functional programming languages. In Chapter 14, we’ll examine Cargo in more @@ -136,7 +142,7 @@ traits that enable their functionality. In Chapter 16, we’ll walk through different models of concurrent programming and talk about how Rust helps you to program in multiple threads fearlessly. -Chapter 17 looks at how Rust idioms compare to object oriented programming +Chapter 17 looks at how Rust idioms compare to object-oriented programming principles you might be familiar with. Chapter 18 is a reference on patterns and pattern matching, which are powerful @@ -148,9 +154,9 @@ In Chapter 20, we’ll complete a project in which we’ll implement a low-level multithreaded web server! Finally, some appendixes contain useful information about the language in a -more reference-like format. Appendix A covers Rust’s keywords. Appendix B -covers Rust’s operators and symbols. Appendix C covers derivable traits -provided by the standard library. Appendix D covers macros. +more reference-like format. Appendix A covers Rust’s keywords, Appendix B +covers Rust’s operators and symbols, Appendix C covers derivable traits +provided by the standard library, and Appendix D covers macros. There is no wrong way to read this book: if you want to skip ahead, go for it! You might have to jump back to earlier chapters if you experience any @@ -158,9 +164,9 @@ confusion. But do whatever works for you. An important part of the process of learning Rust is learning how to read the error messages the compiler displays: these will guide you toward working code. -As such, we’ll provide many examples of code that don’t compile along with the -error message the compiler will show you in each situation. Know that if you -enter and run a random example, it may not compile! Make sure you read the +As such, we’ll provide many examples of code that doesn’t compile along with +the error message the compiler will show you in each situation. Know that if +you enter and run a random example, it may not compile! Make sure you read the surrounding text to see whether the example you’re trying to run is meant to error. In most situations, we’ll lead you to the correct version of any code that doesn’t compile. @@ -170,4 +176,4 @@ that doesn’t compile. The source files from which this book is generated can be found on [GitHub][book]. -[book]: https://github.com/rust-lang/book/tree/master/2018-edition/src \ No newline at end of file +[book]: https://github.com/rust-lang/book/tree/master/second-edition/src diff --git a/src/doc/book/2018-edition/src/ch01-00-getting-started.md b/src/doc/book/2018-edition/src/ch01-00-getting-started.md index e302171c47..ff5e324f7a 100644 --- a/src/doc/book/2018-edition/src/ch01-00-getting-started.md +++ b/src/doc/book/2018-edition/src/ch01-00-getting-started.md @@ -1,12 +1,8 @@ # Getting Started - - +Let’s start your Rust journey! There’s a lot to learn, but every journey starts +somewhere. In this chapter, we’ll discuss: -Let’s get your Rust journey started! In this chapter, we’ll discuss: - -- Installing Rust on Linux, Mac, or Windows -- Writing a program that prints “Hello, world!” -- Using `cargo`, Rust’s package manager and build system +* Installing Rust on Linux, macOS, and Windows +* Writing a program that prints `Hello, world!` +* Using `cargo`, Rust’s package manager and build system diff --git a/src/doc/book/2018-edition/src/ch01-01-installation.md b/src/doc/book/2018-edition/src/ch01-01-installation.md index 2922c872fc..f2c156e938 100644 --- a/src/doc/book/2018-edition/src/ch01-01-installation.md +++ b/src/doc/book/2018-edition/src/ch01-01-installation.md @@ -1,110 +1,96 @@ ## Installation -The first step to using Rust is to install it. We’ll download Rust through -`rustup`, a command-line tool for managing Rust versions and associated tools. -For this you’ll need an internet connection. +The first step is to install Rust. We’ll download Rust through `rustup`, a +command line tool for managing Rust versions and associated tools. You’ll need +an internet connection for the download. -The following steps will install the latest stable version of the Rust -compiler. The examples and output shown in this book all use stable Rust -1.21.0. Rust’s stability guarantees ensure that all of the examples in the book -that compile will continue to compile with newer versions of Rust. The output -may differ slightly between versions, as error messages and warnings are often -improved. In other words, any newer, stable version of Rust you will install -with these steps should work as expected with the content of this book. +> Note: If you prefer not to use `rustup` for some reason, please see [the Rust +> installation page](https://www.rust-lang.org/install.html) for other options. - +The following steps install the latest stable version of the Rust compiler. +Rust’s stability guarantees ensure that all the examples in the book that +compile will continue to compile with newer Rust versions. The output might +differ slightly between versions, because Rust often improves error messages +and warnings. In other words, any newer, stable version of Rust you install +using these steps should work as expected with the content of this book. -> #### Command Line Notation +> ### Command Line Notation > -> In this chapter and throughout the book we’ll be showing some commands used -> in the terminal. Lines that should be entered in a terminal all start with -> `$`. You don’t need to type in the `$` character, it is simply there to -> indicate the start of each command. Many tutorials use this convention: `$` -> for commands run as a regular user, and `#` for commands you should be -> running as an administrator. Lines that don’t start with `$` are typically -> showing the output of the previous command. Additionally, PowerShell specific -> examples will use `>` rather than `$`. +> In this chapter and throughout the book, we’ll show some commands used in the +> terminal. Lines that you should enter in a terminal all start with `$`. You +> don’t need to type in the `$` character; it indicates the start of each +> command. Lines that don’t start with `$` typically show the output of the +> previous command. Additionally, PowerShell-specific examples will use `>` +> rather than `$`. - +### Installing `rustup` on Linux or macOS -### Installing Rustup on Linux or Mac - -If you’re on Linux or a Mac, open a terminal and enter the following command: +If you’re using Linux or macOS, open a terminal and enter the following command: ```text $ curl https://sh.rustup.rs -sSf | sh ``` -This will download a script and start the installation of the `rustup` tool, -which installs the latest stable version of Rust. You may be prompted for your -password. If it all goes well, you’ll see this appear: +The command downloads a script and starts the installation of the `rustup` +tool, which installs the latest stable version of Rust. You might be prompted +for your password. If the install is successful, the following line will appear: ```text Rust is installed now. Great! ``` -Of course, if you distrust using `curl URL | sh` to install software, you can -download, inspect, and run the script however you like. +If you prefer, feel free to download the script and inspect it before running +it. The installation script automatically adds Rust to your system PATH after your next login. If you want to start using Rust right away instead of restarting your terminal, run the following command in your shell to add Rust to your system PATH manually: - - - ```text $ source $HOME/.cargo/env ``` -Alternatively, you can add the following line to your `~/.bash_profile`: +Alternatively, you can add the following line to your *~/.bash_profile*: ```text $ export PATH="$HOME/.cargo/bin:$PATH" ``` -Finally, you’ll need a linker of some kind. It’s likely you already have one -installed, but if you try to compile a Rust program and get errors telling you -that a linker could not be executed, you’ll need to install one. You can -install a C compiler, as that will usually come with the correct linker. Check -your platform’s documentation for how to install a C compiler. Some common Rust -packages depend on C code and will need a C compiler too, so it may be worth -installing one now regardless. +Additionally, you’ll need a linker of some kind. It’s likely one is already +installed, but when you try to compile a Rust program and get errors indicating +that a linker could not execute, that means a linker isn’t installed on your +system and you’ll need to install one manually. C compilers usually come with +the correct linker. Check your platform’s documentation for how to install a C +compiler. Also, some common Rust packages depend on C code and will need a C +compiler. Therefore, it might be worth installing one now. -### Installing Rustup on Windows +### Installing `rustup` on Windows -On Windows, go to [https://www.rust-lang.org/en-US/install.html][install] and -follow the instructions for installing Rust. At some point in the installation -you’ll receive a message telling you you’ll also need the C++ build tools for +On Windows, go to [https://www.rust-lang.org/install.html][install] and follow +the instructions for installing Rust. At some point in the installation, you’ll +receive a message explaining that you’ll also need the C++ build tools for Visual Studio 2013 or later. The easiest way to acquire the build tools is to -install [Build Tools for Visual Studio 2017][visualstudio], found in the Other -Tools and Frameworks section. +install [Build Tools for Visual Studio 2017][visualstudio]. The tools are in +the Other Tools and Frameworks section. -[install]: https://www.rust-lang.org/en-US/install.html +[install]: https://www.rust-lang.org/install.html [visualstudio]: https://www.visualstudio.com/downloads/ -The rest of this book will use commands that work in both `cmd.exe` and -PowerShell. If there are specific differences, we’ll explain which to use. - -### Custom Installations Without Rustup - -If you have reasons for preferring not to use `rustup`, please see [the Rust -installation page](https://www.rust-lang.org/install.html) for other options. +The rest of this book uses commands that work in both *cmd.exe* and PowerShell. +If there are specific differences, we’ll explain which to use. ### Updating and Uninstalling -Once you have Rust installed via `rustup`, updating to the latest version is -easy. From your shell, run the update script: +After you’ve installed Rust via `rustup`, updating to the latest version is +easy. From your shell, run the following update script: ```text $ rustup update ``` -To uninstall Rust and `rustup`, from your shell, run the uninstall script: +To uninstall Rust and `rustup`, run the following uninstall script from your +shell: ```text $ rustup self uninstall @@ -112,31 +98,28 @@ $ rustup self uninstall ### Troubleshooting -To check whether you have Rust installed correctly, open up a shell and enter: +To check whether you have Rust installed correctly, open a shell and enter this +line: ```text $ rustc --version ``` You should see the version number, commit hash, and commit date for the latest -stable version at the time you install in the following format: +stable version that has been released in the following format: ```text rustc x.y.z (abcabcabc yyyy-mm-dd) ``` -If you see this, Rust has been installed successfully! Congrats! - -If you don’t and you’re on Windows, check that Rust is in your `%PATH%` system -variable. - -If that’s all correct and Rust still isn’t working, there are a number of -places you can get help. The easiest is [the #rust IRC channel on +If you see this information, you have installed Rust successfully! If you don’t +see this information and you’re on Windows, check that Rust is in your `%PATH%` +system variable. If that’s all correct and Rust still isn’t working, there are +a number of places you can get help. The easiest is [the #rust IRC channel on irc.mozilla.org][irc], which you can access through -[Mibbit][mibbit]. Go to that address, and you’ll be chatting with other -Rustaceans (a silly nickname we call ourselves) who can help you out. Other -great resources include [the Users forum][users] and [Stack -Overflow][stackoverflow]. +[Mibbit][mibbit]. At that address you can chat with other Rustaceans (a silly +nickname we call ourselves) who can help you out. Other great resources include +[the Users forum][users] and [Stack Overflow][stackoverflow]. [irc]: irc://irc.mozilla.org/#rust [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust @@ -149,6 +132,6 @@ The installer also includes a copy of the documentation locally, so you can read it offline. Run `rustup doc` to open the local documentation in your browser. -Any time there’s a type or function provided by the standard library and you’re -not sure what it does or how to use it, use the API (Application Programming -Interface) documentation to find out! +Any time a type or function is provided by the standard library and you’re not +sure what it does or how to use it, use the application programming interface +(API) documentation to find out! diff --git a/src/doc/book/2018-edition/src/ch01-02-hello-world.md b/src/doc/book/2018-edition/src/ch01-02-hello-world.md index 7c278d6b0e..0129cf0f0d 100644 --- a/src/doc/book/2018-edition/src/ch01-02-hello-world.md +++ b/src/doc/book/2018-edition/src/ch01-02-hello-world.md @@ -1,28 +1,28 @@ ## Hello, World! -Now that you have Rust installed, let’s write your first Rust program. It’s -traditional when learning a new language to write a little program to print the -text “Hello, world!” to the screen, so we’ll do the same here! +Now that you’ve installed Rust, let’s write your first Rust program. It’s +traditional when learning a new language to write a little program that prints +the text `Hello, world!` to the screen, so we’ll do the same here! -> Note: This book assumes basic familiarity with the command line. Rust itself -> makes no specific demands about your editing, tooling, or where your code -> lives, so if you prefer an IDE (Integrated Development Environment) to the -> command line, feel free to use your favorite IDE. Many IDEs now have some -> degree of Rust support; check the IDE’s documentation for details. Enabling -> great IDE support has been a recent focus of the Rust team, and progress +> Note: This book assumes basic familiarity with the command line. Rust makes +> no specific demands about your editing or tooling or where your code lives, so +> if you prefer to use an integrated development environment (IDE) instead of +> the command line, feel free to use your favorite IDE. Many IDEs now have some +> degree of Rust support; check the IDE’s documentation for details. Recently, +> the Rust team has been focusing on enabling great IDE support, and progress > has been made rapidly on that front! ### Creating a Project Directory -First, make a directory to put your Rust code in. Rust doesn’t care where your -code lives, but for the exercises and projects in this book, we’d suggest -making a *projects* directory in your home directory and keeping all your -projects there. +You’ll start by making a directory to store your Rust code. It doesn’t matter +to Rust where your code lives, but for the exercises and projects in this book, +we suggest making a *projects* directory in your home directory and keeping all +your projects there. Open a terminal and enter the following commands to make a *projects* directory -and, inside that, a directory for this “Hello, world!” project: +and a directory for the Hello, world! project within the *projects* directory. -Linux and Mac: +For Linux and macOS, enter this: ```text $ mkdir ~/projects @@ -31,7 +31,7 @@ $ mkdir hello_world $ cd hello_world ``` -Windows CMD: +For Windows CMD, enter this: ```cmd > mkdir "%USERPROFILE%\projects" @@ -40,7 +40,7 @@ Windows CMD: > cd hello_world ``` -Windows PowerShell: +For Windows PowerShell, enter this: ```powershell > mkdir $env:USERPROFILE\projects @@ -51,13 +51,12 @@ Windows PowerShell: ### Writing and Running a Rust Program -Next, make a new source file and call it *main.rs*---Rust files always end with +Next, make a new source file and call it *main.rs*. Rust files always end with the *.rs* extension. If you’re using more than one word in your filename, use -an underscore to separate them. For example, you’d use *hello_world.rs* rather -than *helloworld.rs*. +an underscore to separate them. For example, use *hello_world.rs* rather than +*helloworld.rs*. -Now open the *main.rs* file you just created, and enter the code shown in -Listing 1-1: +Now open the *main.rs* file you just created and enter the code in Listing 1-1. Filename: main.rs @@ -67,9 +66,9 @@ fn main() { } ``` -Listing 1-1: A program that prints “Hello, world!” +Listing 1-1: A program that prints `Hello, world!` -Save the file, and go back to your terminal window. On Linux or macOS, enter +Save the file and go back to your terminal window. On Linux or macOS, enter the following commands to compile and run the file: ```text @@ -78,7 +77,7 @@ $ ./main Hello, world! ``` -On Windows, use `.\main.exe` instead of `./main`. +On Windows, enter the command `.\main.exe` instead of `./main`: ```powershell > rustc main.rs @@ -86,22 +85,17 @@ On Windows, use `.\main.exe` instead of `./main`. Hello, world! ``` -Regardless of your operating system, you should see the string `Hello, world!` -print to the terminal. If you don’t see this output, see the “Troubleshooting” -section earlier for ways to get help. +Regardless of your operating system, the string `Hello, world!` should print to +the terminal. If you don’t see this output, refer back to the “Troubleshooting” +part of the Intstallation section for ways to get help. -If you did see `Hello, world!` printed, then congratulations! You’ve officially -written a Rust program. That makes you a Rust programmer! Welcome! - - - +If `Hello, world!` did print, congratulations! You’ve officially written a Rust +program. That makes you a Rust programmer—welcome! ### Anatomy of a Rust Program -Now, let’s go over what just happened in your “Hello, world!” program in -detail. Here’s the first piece of the puzzle: +Let’s review in detail what just happened in your Hello, world! program. +Here’s the first piece of the puzzle: ```rust fn main() { @@ -109,81 +103,86 @@ fn main() { } ``` -These lines define a *function* in Rust. The `main` function is special: it is -always the first code that is run for every executable Rust program. The first +These lines define a function in Rust. The `main` function is special: it is +always the first code that runs in every executable Rust program. The first line declares a function named `main` that has no parameters and returns -nothing. If there were parameters, their names would go inside the parentheses, -`(` and `)`. +nothing. If there were parameters, they would go inside the parentheses, `()`. -Also note that the function body is wrapped in curly brackets, `{` and `}`. -Rust requires these around all function bodies. It’s considered good style to -place the opening curly bracket on the same line as the function declaration, -with one space in between. +Also, note that the function body is wrapped in curly brackets, `{}`. Rust +requires these around all function bodies. It’s good style to place the opening +curly bracket on the same line as the function declaration, adding one space in +between. -> At the time of writing, an automatic formatter, `rustfmt`, is under -> development. If you’d like to stick to a standard style across Rust projects, -> `rustfmt` is a tool that will format your code in a particular style. The -> plan is to eventually include it with the standard Rust distribution, like -> `rustc`, so depending on when you read this book, you may have it already -> installed! Check the online documentation for more details. +At the time of this writing, an automatic formatter tool called `rustfmt` is +under development. If you want to stick to a standard style across Rust +projects, `rustfmt` will format your code in a particular style. The Rust team +plans to eventually include this tool with the standard Rust distribution, like +`rustc`. So depending on when you read this book, it might already be installed +on your computer! Check the online documentation for more details. -Inside the `main` function, we have this code: +Inside the `main` function is the following code: ```rust println!("Hello, world!"); ``` -This line does all of the work in this little program: it prints text to the -screen. There are a number of details to notice here. The first is that Rust -style is to indent with four spaces, not a tab. +This line does all the work in this little program: it prints text to the +screen. There are four important details to notice here. First, Rust style is +to indent with four spaces, not a tab. -The second important detail is the `println!` call. This code is calling a Rust -*macro*. If it were calling a function instead, it would be entered as -`println` (without the `!`). We’ll discuss Rust macros in more detail in -Appendix D, but for now you just need to know that when you see a `!` that +Second, `println!` calls a Rust macro. If it called a function instead, it +would be entered as `println` (without the `!`). We’ll discuss Rust macros in +more detail in Appendix D. For now, you just need to know that using a `!` means that you’re calling a macro instead of a normal function. - - +Third, you see the `"Hello, world!"` string. We pass this string as an argument +to `println!`, and the string is printed to the screen. -Next comes`"Hello, world!"` which is a *string*. We pass this string as an -argument to `println!` and the total effect is that the string is printed to -the screen. Easy enough! - -We end the line with a semicolon `;`, which indicates that this expression is -over, and the next one is ready to begin. Most lines of Rust code end with a -`;`. +Fourth, we end the line with a semicolon (`;`), which indicates that this +expression is over and the next one is ready to begin. Most lines of Rust code +end with a semicolon. ### Compiling and Running Are Separate Steps -You’ve just seen how to run a newly created program, so now let’s break that -process down and examine each step. +You’ve just run a newly created program, so let’s examine each step in the +process. -Before running a Rust program, you have to compile it using the Rust compiler -by entering the `rustc` command and passing it the name of your source file, -like this: +Before running a Rust program, you must compile it using the Rust compiler by +entering the `rustc` command and passing it the name of your source file, like +this: ```text $ rustc main.rs ``` -If you come from a C or C++ background, you’ll notice that this is similar to -`gcc` or `clang`. After compiling successfully, Rust outputs a binary -executable. +If you have a C or C++ background, you’ll notice that this is similar to `gcc` +or `clang`. After compiling successfully, Rust outputs a binary executable. -On Linux, Mac, and PowerShell on Windows, you can see the executable by -entering the `ls` command in your shell as follows: +On Linux and macOS you can see the executable by entering the `ls` command in +your shell as follows: ```text $ ls main main.rs ``` -With CMD on Windows, you’d enter: +With PowerShell on Windows, you can use `ls` as well, but you'll see three files: + +```text +> ls + + + Directory: Path:\to\the\project + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 6/1/2018 7:31 AM 137728 main.exe +-a---- 6/1/2018 7:31 AM 1454080 main.pdb +-a---- 6/1/2018 7:31 AM 14 main.rs +``` + +With CMD on Windows, you would enter the following: ```cmd > dir /B %= the /B option says to only show the file names =% @@ -192,27 +191,28 @@ main.pdb main.rs ``` -This shows we have two files: the source code, with the *.rs* extension, and -the executable (*main.exe* on Windows, *main* everywhere else). All that’s left -to do from here is run the *main* or *main.exe* file, like this: +This shows the source code file with the *.rs* extension, the executable file +(*main.exe* on Windows, but *main* on all other platforms), and, when using +CMD, a file containing debugging information with the *.pdb* extension. From +here, you run the *main* or *main.exe* file, like this: ```text -$ ./main # or .\main.exe on Windows +$ ./main # or .\main.exe on Windows ``` -If *main.rs* were your “Hello, world!” program, this would print `Hello, +If *main.rs* was your Hello, world! program, this line would print `Hello, world!` to your terminal. -If you come from a dynamic language like Ruby, Python, or JavaScript, you may -not be used to compiling and running a program being separate steps. Rust is an -*ahead-of-time compiled* language, which means that you can compile a program, -give the executable to someone else, and they can run it even without having -Rust installed. If you give someone a `.rb`, `.py`, or `.js` file, on the other -hand, they need to have a Ruby, Python, or JavaScript implementation installed -(respectively), but you only need one command to both compile and run your -program. Everything is a tradeoff in language design. +If you’re more familiar with a dynamic language, such as Ruby, Python, or +JavaScript, you might not be used to compiling and running a program as +separate steps. Rust is an *ahead-of-time compiled* language, meaning you can +compile a program and give the executable to someone else, and they can run it +even without having Rust installed. If you give someone a *.rb*, *.py*, or +*.js* file, they need to have a Ruby, Python, or JavaScript implementation +installed (respectively). But in those languages, you only need one command to +compile and run your program. Everything is a trade-off in language design. Just compiling with `rustc` is fine for simple programs, but as your project -grows, you’ll want to be able to manage all of the options and make it easy to -share your code. Next, we’ll introduce you to a tool called Cargo, which will -help you write real-world Rust programs. +grows, you’ll want to manage all the options and make it easy to share your +code. Next, we’ll introduce you to the Cargo tool, which will help you write +real-world Rust programs. diff --git a/src/doc/book/2018-edition/src/ch01-03-hello-cargo.md b/src/doc/book/2018-edition/src/ch01-03-hello-cargo.md index c2206767bd..38a8d89bb7 100644 --- a/src/doc/book/2018-edition/src/ch01-03-hello-cargo.md +++ b/src/doc/book/2018-edition/src/ch01-03-hello-cargo.md @@ -1,71 +1,57 @@ ## Hello, Cargo! -Cargo is Rust’s build system and package manager. Most Rustaceans will use this -tool to manage their Rust projects because Cargo takes care of a lot of tasks -for you, such as building your code, downloading the libraries your code -depends on, and building those libraries. (We call libraries your code needs -*dependencies*.) +Cargo is Rust’s build system and package manager. Most Rustaceans use this tool +to manage their Rust projects because Cargo handles a lot of tasks for you, +such as building your code, downloading the libraries your code depends on, and +building those libraries. (We call libraries your code needs *dependencies*.) The simplest Rust programs, like the one we’ve written so far, don’t have any -dependencies, so if we had built the Hello World project with Cargo, it would -only be using the part of Cargo that takes care of building your code. As you -write more complex Rust programs, you’ll want to add dependencies, and if you -start the project off using Cargo, that will be a lot easier to do. +dependencies. So if we had built the Hello, world! project with Cargo, it would +only use the part of Cargo that handles building your code. As you write more +complex Rust programs, you’ll add dependencies, and if you start a project +using Cargo, adding dependencies will be much easier to do. -As the vast majority of Rust projects use Cargo, the rest of this book will -assume that you’re using Cargo too. Cargo comes installed with Rust itself, if -you used the official installers as covered in the “Installation” section. If -you installed Rust through some other means, you can check if you have Cargo -installed by entering the following into your terminal: +Because the vast majority of Rust projects use Cargo, the rest of this book +assumes that you’re using Cargo too. Cargo comes installed with Rust if you +used the official installers discussed in the “Installation” section. If you +installed Rust through some other means, check whether Cargo is installed by +entering the following into your terminal: ```text $ cargo --version ``` -If you see a version number, great! If you see an error like `command not -found`, then you should look at the documentation for your method of -installation to determine how to install Cargo separately. +If you see a version number, you have it! If you see an error, such as `command +not found`, look at the documentation for your method of installation to +determine how to install Cargo separately. ### Creating a Project with Cargo Let’s create a new project using Cargo and look at how it differs from our -original Hello World project. Navigate back to your *projects* directory (or -whichever location you decided to place your code) and then on any operating -system run: +original Hello, world! project. Navigate back to your *projects* directory (or +wherever you decided to store your code). Then, on any operating system, run +the following: ```text -$ cargo new hello_cargo --bin +$ cargo new hello_cargo $ cd hello_cargo ``` - - +The first command creates a new directory called *hello_cargo*. We’ve named +our project *hello_cargo*, and Cargo creates its files in a directory of the +same name. -This creates a new binary executable called `hello_cargo`. The `--bin` argument -to passed to `cargo new` makes an executable application (often just called a -*binary*), as opposed to a library. We’ve given `hello_cargo` as the name for -our project, and Cargo creates its files in a directory of the same name. - -Go into the *hello_cargo* directory and list the files, and you should see that -Cargo has generated two files and one directory for us: a *Cargo.toml* and a -*src* directory with a *main.rs* file inside. It has also initialized a new git -repository, along with a *.gitignore* file. +Go into the *hello_cargo* directory and list the files. You’ll see that Cargo +has generated two files and one directory for us: a *Cargo.toml* file and a +*src* directory with a *main.rs* file inside. It has also initialized a new Git +repository along with a *.gitignore* file. > Note: Git is a common version control system. You can change `cargo new` to -> use a different version control system, or no version control system, by -> using the `--vcs` flag. Run `cargo new --help` to see the available options. +> use a different version control system or no version control system by using +> the `--vcs` flag. Run `cargo new --help` to see the available options. -Open up *Cargo.toml* in your text editor of choice. It should look similar to -the code in Listing 1-2: +Open *Cargo.toml* in your text editor of choice. It should look similar to the +code in Listing 1-2. Filename: Cargo.toml @@ -81,8 +67,8 @@ authors = ["Your Name "] Listing 1-2: Contents of *Cargo.toml* generated by `cargo new` -This file is in the [*TOML*][toml] (Tom’s Obvious, Minimal -Language) format, which is what Cargo uses as its configuration format. +This file is in the [*TOML*][toml] (*Tom’s Obvious, Minimal +Language*) format, which is Cargo’s configuration format. [toml]: https://github.com/toml-lang/toml @@ -90,17 +76,17 @@ The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other sections. -The next three lines set the configuration information Cargo needs in order to -know that it should compile your program: the name, the version, and who wrote -it. Cargo gets your name and email information from your environment, so if -that’s not correct, go ahead and fix that and save the file. +The next three lines set the configuration information Cargo needs to compile +your program: the name, the version, and who wrote it. Cargo gets your name and +email information from your environment, so if that information is not correct, +fix the information now and then save the file. The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Rust, packages of code are referred to as *crates*. We won’t need any other crates for this project, but we will in the first project in Chapter 2, so we’ll use this dependencies section then. -Now open up *src/main.rs* and take a look: +Now open *src/main.rs* and take a look: Filename: src/main.rs @@ -110,27 +96,27 @@ fn main() { } ``` -Cargo has generated a “Hello World!” for you, just like the one we wrote in -Listing 1-1! So far, the differences between our previous project and the -project generated by Cargo are that with Cargo our code goes in the *src* -directory, and we have a *Cargo.toml* configuration file in the top directory. +Cargo has generated a Hello, world! program for you, just like the one we wrote +in Listing 1-1! So far, the differences between our previous project and the +project Cargo generates are that Cargo placed the code in the *src* directory, +and we have a *Cargo.toml* configuration file in the top directory. -Cargo expects your source files to live inside the *src* directory; the -top-level project directory is just for READMEs, license information, -configuration files, and anything else not related to your code. In this way, -using Cargo helps you keep your projects nice and tidy. There’s a place for -everything, and everything is in its place. +Cargo expects your source files to live inside the *src* directory. The +top-level project directory is just for README files, license information, +configuration files, and anything else not related to your code. Using Cargo +helps you organize your projects. There’s a place for everything, and +everything is in its place. -If you started a project that doesn’t use Cargo, as we did with our project in -the *hello_world* directory, you can convert it to a project that does use -Cargo by moving the project code into the *src* directory and creating an -appropriate *Cargo.toml*. +If you started a project that doesn’t use Cargo, as we did with the Hello, +world! project, you can convert it to a project that does use Cargo. Move the +project code into the *src* directory and create an appropriate *Cargo.toml* +file. ### Building and Running a Cargo Project -Now let’s look at what’s different about building and running your Hello World -program through Cargo! From your project directory, build your project by -entering the following commands: +Now let’s look at what’s different when we build and run the Hello, world! +program with Cargo! From your *hello_cargo* directory, build your project by +entering the following command: ```text $ cargo build @@ -138,25 +124,25 @@ $ cargo build Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs ``` -This creates an executable file in *target/debug/hello_cargo* (or -*target\\debug\\hello_cargo.exe* on Windows), which you can run with this -command: +This command creates an executable file in *target/debug/hello_cargo* (or +*target\debug\hello_cargo.exe* on Windows) rather than in your current +directory. You can run the executable with this command: ```text $ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows Hello, world! ``` -Bam! If all goes well, `Hello, world!` should print to the terminal once more. -Running `cargo build` for the first time also causes Cargo to create a new file -at the top level called *Cargo.lock*, which is used to keep track of the exact -versions of dependencies in your project. This project doesn’t have -dependencies, so the file is a bit sparse. You won’t ever need to touch this -file yourself; Cargo will manage its contents for you. +If all goes well, `Hello, world!` should print to the terminal. Running `cargo +build` for the first time also causes Cargo to create a new file at the top +level: *Cargo.lock*. This file keeps track of the exact versions of +dependencies in your project. This project doesn’t have dependencies, so the +file is a bit sparse. You won’t ever need to change this file manually; Cargo +manages its contents for you. We just built a project with `cargo build` and ran it with -`./target/debug/hello_cargo`, but we can also use `cargo run` to compile and -then run all in one go: +`./target/debug/hello_cargo`, but we can also use `cargo run` to compile the +code and then run the resulting executable all in one command: ```text $ cargo run @@ -165,10 +151,10 @@ $ cargo run Hello, world! ``` -Notice that this time, we didn’t see the output telling us that Cargo was -compiling `hello_cargo`. Cargo figured out that the files haven’t changed, so -it just ran the binary. If you had modified your source code, Cargo would have -rebuilt the project before running it, and you would have seen output like this: +Notice that this time we didn’t see output indicating that Cargo was compiling +`hello_cargo`. Cargo figured out that the files hadn’t changed, so it just ran +the binary. If you had modified your source code, Cargo would have rebuilt the +project before running it, and you would have seen this output: ```text $ cargo run @@ -178,8 +164,8 @@ $ cargo run Hello, world! ``` -Finally, there’s `cargo check`. This command will quickly check your code to -make sure that it compiles, but not bother producing an executable: +Cargo also provides a command called `cargo check`. This command quickly checks +your code to make sure it compiles but doesn’t produce an executable: ```text $ cargo check @@ -187,48 +173,48 @@ $ cargo check Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs ``` -Why would you not want an executable? `cargo check` is often much faster than -`cargo build`, because it skips the entire step of producing the executable. If -you’re checking your work throughout the process of writing the code, using -`cargo check` will speed things up! As such, many Rustaceans run `cargo check` -periodically as they write their program to make sure that it compiles, and -then run `cargo build` once they’re ready to give it a spin themselves. +Why would you not want an executable? Often, `cargo check` is much faster than +`cargo build`, because it skips the step of producing an executable. If you’re +continually checking your work while writing the code, using `cargo check` will +speed up the process! As such, many Rustaceans run `cargo check` periodically +as they write their program to make sure it compiles. Then they run `cargo +build` when they’re ready to use the executable. -So to recap, using Cargo: +Let’s recap what we’ve learned so far about Cargo: -- We can build a project using `cargo build` or `cargo check` -- We can build and run the project in one step with `cargo run` -- Instead of the result of the build being put in the same directory as our - code, Cargo will put it in the *target/debug* directory. +* We can build a project using `cargo build` or `cargo check`. +* We can build and run a project in one step using `cargo run`. +* Instead of saving the result of the build in the same directory as our code, + Cargo stores it in the *target/debug* directory. -A final advantage of using Cargo is that the commands are the same no matter -what operating system you’re on, so at this point we will no longer be -providing specific instructions for Linux and Mac versus Windows. +An additional advantage of using Cargo is that the commands are the same no +matter which operating system you’re working on. So, at this point, we’ll no +longer provide specific instructions for Linux and macOS versus Windows. ### Building for Release When your project is finally ready for release, you can use `cargo build ---release` to compile your project with optimizations. This will create an -executable in *target/release* instead of *target/debug*. These optimizations -make your Rust code run faster, but turning them on increases the compilation -time of your program. This is why there are two different profiles: one for -development when you want to be able to rebuild quickly and often, and one for +--release` to compile it with optimizations. This command will create an +executable in *target/release* instead of *target/debug*. The optimizations +make your Rust code run faster, but turning them on lengthens the time it takes +for your program to compile. This is why there are two different profiles: one +for development, when you want to rebuild quickly and often, and another for building the final program you’ll give to a user that won’t be rebuilt -repeatedly and that will run as fast as possible. If you’re benchmarking the -running time of your code, be sure to run `cargo build --release` and benchmark -with the executable in *target/release*. +repeatedly and that will run as fast as possible. If you’re benchmarking your +code’s running time, be sure to run `cargo build --release` and benchmark with +the executable in *target/release*. ### Cargo as Convention -With simple projects, Cargo doesn’t provide a whole lot of value over just -using `rustc`, but it will prove its worth as you continue. With complex -projects composed of multiple crates, it’s much easier to let Cargo coordinate -the build. +With simple projects, Cargo doesn’t provide a lot of value over just using +`rustc`, but it will prove its worth as your programs become more intricate. +With complex projects composed of multiple crates, it’s much easier to let +Cargo coordinate the build. Even though the `hello_cargo` project is simple, it now uses much of the real -tooling you’ll use for the rest of your Rust career. In fact, to work on any -existing projects you can use the following commands to check out the code -using Git, change into the project directory, and build: +tooling you’ll use in the rest of your Rust career. In fact, to work on any +existing projects, you can use the following commands to check out the code +using Git, change to that project’s directory, and build: ```text $ git clone someurl.com/someproject @@ -236,31 +222,22 @@ $ cd someproject $ cargo build ``` -If you want to look at Cargo in more detail, check out [its documentation]. +For more information about Cargo, check out [its documentation]. [its documentation]: https://doc.rust-lang.org/cargo/ - - - ## Summary You’re already off to a great start on your Rust journey! In this chapter, -you’ve: +you’ve learned how to: -* Installed the latest stable version of Rust -* Written a “Hello, world!” program using both `rustc` directly and using - the conventions of `cargo` +* Install the latest stable version of Rust using `rustup` +* Update to a newer Rust version +* Open locally installed documentation +* Write and run a Hello, world! program using `rustc` directly +* Create and run a new project using the conventions of Cargo -This is a great time to build a more substantial program, to get used to -reading and writing Rust code. In the next chapter, we’ll build a guessing game -program. If you’d rather start by learning about how common programming -concepts work in Rust, see Chapter 3. +This is a great time to build a more substantial program to get used to reading +and writing Rust code. So, in Chapter 2, we’ll build a guessing game program. +If you would rather start by learning how common programming concepts work in +Rust, see Chapter 3 and then return to Chapter 2. diff --git a/src/doc/book/2018-edition/src/ch02-00-guessing-game-tutorial.md b/src/doc/book/2018-edition/src/ch02-00-guessing-game-tutorial.md index a399afb982..68f5b5a3d1 100644 --- a/src/doc/book/2018-edition/src/ch02-00-guessing-game-tutorial.md +++ b/src/doc/book/2018-edition/src/ch02-00-guessing-game-tutorial.md @@ -18,13 +18,12 @@ To set up a new project, go to the *projects* directory that you created in Chapter 1 and make a new project using Cargo, like so: ```text -$ cargo new guessing_game --bin +$ cargo new guessing_game $ cd guessing_game ``` The first command, `cargo new`, takes the name of the project (`guessing_game`) -as the first argument. The `--bin` flag tells Cargo to make a binary project, -like the one in Chapter 1. The second command changes to the new project’s +as the first argument. The second command changes to the new project’s directory. Look at the generated *Cargo.toml* file: @@ -155,11 +154,11 @@ line. Notice that this is a `let` statement, which is used to create a let foo = bar; ``` -This line creates a new variable named `foo` and bind it to the value `bar`. In -Rust, variables are immutable by default. We’ll be discussing this concept in -detail in the “Variables and Mutability” section in Chapter 3. The following -example shows how to use `mut` before the variable name to make a variable -mutable: +This line creates a new variable named `foo` and binds it to the value of the +`bar` variable. In Rust, variables are immutable by default. We’ll be +discussing this concept in detail in the “Variables and Mutability” section in +Chapter 3. The following example shows how to use `mut` before the variable +name to make a variable mutable: ```rust,ignore let foo = 5; // immutable @@ -685,8 +684,8 @@ Could not compile `guessing_game`. The core of the error states that there are *mismatched types*. Rust has a strong, static type system. However, it also has type inference. When we wrote -`let guess = String::new()`, Rust was able to infer that `guess` should be a -`String` and didn’t make us write the type. The `secret_number`, on the other +`let mut guess = String::new();`, Rust was able to infer that `guess` should be +a `String` and didn’t make us write the type. The `secret_number`, on the other hand, is a number type. A few number types can have a value between 1 and 100: `i32`, a 32-bit number; `u32`, an unsigned 32-bit number; `i64`, a 64-bit number; as well as others. Rust defaults to an `i32`, which is the type of diff --git a/src/doc/book/2018-edition/src/ch03-01-variables-and-mutability.md b/src/doc/book/2018-edition/src/ch03-01-variables-and-mutability.md index 45243e7d24..58bdac8fc7 100644 --- a/src/doc/book/2018-edition/src/ch03-01-variables-and-mutability.md +++ b/src/doc/book/2018-edition/src/ch03-01-variables-and-mutability.md @@ -9,7 +9,7 @@ out. When a variable is immutable, once a value is bound to a name, you can’t change that value. To illustrate this, let’s generate a new project called *variables* -in your *projects* directory by using `cargo new --bin variables`. +in your *projects* directory by using `cargo new variables`. Then, in your new *variables* directory, open *src/main.rs* and replace its code with the following code that won’t compile just yet: diff --git a/src/doc/book/2018-edition/src/ch03-02-data-types.md b/src/doc/book/2018-edition/src/ch03-02-data-types.md index dfdbfcd092..5b049d305a 100644 --- a/src/doc/book/2018-edition/src/ch03-02-data-types.md +++ b/src/doc/book/2018-edition/src/ch03-02-data-types.md @@ -50,13 +50,14 @@ value. Table 3-1: Integer Types in Rust -| Length | Signed | Unsigned | -|--------|---------|----------| -| 8-bit | `i8` | `u8` | -| 16-bit | `i16` | `u16` | -| 32-bit | `i32` | `u32` | -| 64-bit | `i64` | `u64` | -| arch | `isize` | `usize` | +| Length | Signed | Unsigned | +|---------|---------|----------| +| 8-bit | `i8` | `u8` | +| 16-bit | `i16` | `u16` | +| 32-bit | `i32` | `u32` | +| 64-bit | `i64` | `u64` | +| 128-bit | `i128` | `u128` | +| arch | `isize` | `usize` | Each variant can be either signed or unsigned and has an explicit size. *Signed* and *unsigned* refer to whether it’s possible for the number to be @@ -98,6 +99,21 @@ defaults are generally good choices, and integer types default to `i32`: this type is generally the fastest, even on 64-bit systems. The primary situation in which you’d use `isize` or `usize` is when indexing some sort of collection. +##### Integer Overflow + +Let's say that you have a `u8`, which can hold values between zero and `255`. +What happens if you try to change it to `256`? This is called "integer +overflow", and Rust has some interesting rules around this behavior. When +compiling in debug mode, Rust checks for this kind of issue and will cause +your program to *panic*, which is the term Rust uses when a program exits +with an error. We'll discuss panics more in Chapter 9. + +In release builds, Rust does not check for overflow, and instead will +do something called "two's compliment wrapping." In short, `256` becomes +`0`, `257` becomes `1`, etc. Relying on overflow is considered an error, +even if this behavior happens. If you want this behavior explicitly, the +standard library has a type, `Wrapping`, that provides it explicitly. + #### Floating-Point Types Rust also has two primitive types for *floating-point numbers*, which are @@ -172,12 +188,14 @@ The main way to consume Boolean values is through conditionals, such as an `if` expression. We’ll cover how `if` expressions work in Rust in the “Control Flow” section. +Booleans are one byte in size. + #### The Character Type So far we’ve worked only with numbers, but Rust supports letters too. Rust’s `char` type is the language’s most primitive alphabetic type, and the following -code shows one way to use it. (Note that the `char` type is specified with -single quotes, as opposed to strings, which use double quotes.) +code shows one way to use it. (Note that the `char` literal is specified with +single quotes, as opposed to string literals, which use double quotes.) Filename: src/main.rs @@ -204,8 +222,9 @@ primitive compound types: tuples and arrays. #### The Tuple Type -A tuple is a general way of grouping together some number of other values with -a variety of types into one compound type. +A tuple is a general way of grouping together some number of other values +with a variety of types into one compound type. Tuples have a fixed length: +once declared, they cannot grow or shrink in size. We create a tuple by writing a comma-separated list of values inside parentheses. Each position in the tuple has a type, and the types of the @@ -269,7 +288,7 @@ index in a tuple is 0. Another way to have a collection of multiple values is with an *array*. Unlike a tuple, every element of an array must have the same type. Arrays in Rust are different from arrays in some other languages because arrays in Rust have a -fixed length: once declared, they cannot grow or shrink in size. +fixed length, like tuples. In Rust, the values going into an array are written as a comma-separated list inside square brackets: @@ -300,6 +319,21 @@ let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; ``` +Arrays have an interesting type; it looks like this: `[type; number]`. For +example: + +```rust +let a: [i32; 5] = [1, 2, 3, 4, 5]; +``` + +First, there's square brackets; they look like the syntax for creating an +array. Inside, there's two pieces of information, separated by a semicolon. +The first is the type of each element of the array. Since all elements have +the same type, we only need to list it once. After the semicolon, there's +a number that indicates the length of the array. Since an array has a fixed size, +this number is always the same, even if the array's elements are modified, it +cannot grow or shrink. + ##### Accessing Array Elements An array is a single chunk of memory allocated on the stack. You can access @@ -355,7 +389,7 @@ The compilation didn’t produce any errors, but the program resulted in a *runtime* error and didn’t exit successfully. When you attempt to access an element using indexing, Rust will check that the index you’ve specified is less than the array length. If the index is greater than the length, Rust will -*panic*, which is the term Rust uses when a program exits with an error. +panic. This is the first example of Rust’s safety principles in action. In many low-level languages, this kind of check is not done, and when you provide an diff --git a/src/doc/book/2018-edition/src/ch03-03-how-functions-work.md b/src/doc/book/2018-edition/src/ch03-03-how-functions-work.md index 5bf722342b..3650f9e63a 100644 --- a/src/doc/book/2018-edition/src/ch03-03-how-functions-work.md +++ b/src/doc/book/2018-edition/src/ch03-03-how-functions-work.md @@ -320,7 +320,7 @@ fn plus_one(x: i32) -> i32 { } ``` -Running this code produces an error, as follows: +Compiling this code produces an error, as follows: ```text error[E0308]: mismatched types diff --git a/src/doc/book/2018-edition/src/ch03-05-control-flow.md b/src/doc/book/2018-edition/src/ch03-05-control-flow.md index ee8d77e3a3..b6bde5e907 100644 --- a/src/doc/book/2018-edition/src/ch03-05-control-flow.md +++ b/src/doc/book/2018-edition/src/ch03-05-control-flow.md @@ -226,7 +226,7 @@ fn main() { } ``` -When we try to run this code, we’ll get an error. The `if` and `else` arms have +When we try to compile this code, we’ll get an error. The `if` and `else` arms have value types that are incompatible, and Rust indicates exactly where to find the problem in the program: @@ -309,6 +309,30 @@ stop executing the loop. Recall that we did this in the guessing game in the “Quitting After a Correct Guess” section of Chapter 2 to exit the program when the user won the game by guessing the correct number. + +#### Returning from loops + +One of the uses of a `loop` is to retry an operation you know can fail, such as +checking if a thread completed its job. However, you might need to pass the +result of that operation to the rest of your code. If you add it to the `break` +expression you use to stop the loop, it will be returned by the broken loop: + +```rust +fn main() { + let mut counter = 0; + + let result = loop { + counter += 1; + + if counter == 10 { + break counter * 2; + } + }; + + assert_eq!(result, 20); +} +``` + #### Conditional Loops with `while` It’s often useful for a program to evaluate a condition within a loop. While diff --git a/src/doc/book/2018-edition/src/ch04-03-slices.md b/src/doc/book/2018-edition/src/ch04-03-slices.md index 5bf3fec304..1abb53654e 100644 --- a/src/doc/book/2018-edition/src/ch04-03-slices.md +++ b/src/doc/book/2018-edition/src/ch04-03-slices.md @@ -150,7 +150,18 @@ let world = &s[6..11]; This is similar to taking a reference to the whole `String` but with the extra `[0..5]` bit. Rather than a reference to the entire `String`, it’s a reference to a portion of the `String`. The `start..end` syntax is a range that begins at -`start` and continues up to, but not including, `end`. +`start` and continues up to, but not including, `end`. If we wanted to include +`end`, we can use `..=` instead of `..`: + +```rust +let s = String::from("hello world"); + +let hello = &s[0..=4]; +let world = &s[6..=10]; +``` + +The `=` means that we're including the last number, if that helps you remember +the difference between `..` and `..=`. We can create slices using a range within brackets by specifying `[starting_index..ending_index]`, where `starting_index` is the first position @@ -158,7 +169,7 @@ in the slice and `ending_index` is one more than the last position in the slice. Internally, the slice data structure stores the starting position and the length of the slice, which corresponds to `ending_index` minus `starting_index`. So in the case of `let world = &s[6..11];`, `world` would be -a slice that contains a pointer to the 6th byte of `s` and a length value of 5. +a slice that contains a pointer to the 7th byte of `s` and a length value of 5. Figure 4-6 shows this in a diagram. diff --git a/src/doc/book/2018-edition/src/ch07-01-mod-and-the-filesystem.md b/src/doc/book/2018-edition/src/ch07-01-mod-and-the-filesystem.md index e5e3718a85..4b9d34d191 100644 --- a/src/doc/book/2018-edition/src/ch07-01-mod-and-the-filesystem.md +++ b/src/doc/book/2018-edition/src/ch07-01-mod-and-the-filesystem.md @@ -10,7 +10,7 @@ We’ll create a skeleton of a library that provides some general networking functionality; we’ll concentrate on the organization of the modules and functions, but we won’t worry about what code goes in the function bodies. We’ll call our library `communicator`. To create a library, pass the `--lib` -option instead of `--bin`: +option: ```text $ cargo new communicator --lib @@ -32,8 +32,7 @@ mod tests { } ``` -Cargo creates an example test to help us get our library started, rather than -the “Hello, world!” binary that we get when we use the `--bin` option. We’ll +Cargo creates an example test to help us get our library started. We’ll look at the `#[]` and `mod tests` syntax in the “Using `super` to Access a Parent Module” section later in this chapter, but for now, leave this code at the bottom of *src/lib.rs*. diff --git a/src/doc/book/2018-edition/src/ch07-03-importing-names-with-use.md b/src/doc/book/2018-edition/src/ch07-03-importing-names-with-use.md index 4f3d258f07..1bc7419506 100644 --- a/src/doc/book/2018-edition/src/ch07-03-importing-names-with-use.md +++ b/src/doc/book/2018-edition/src/ch07-03-importing-names-with-use.md @@ -104,6 +104,39 @@ fn main() { We’re still specifying the `TrafficLight` namespace for the `Green` variant because we didn’t include `Green` in the `use` statement. +#### Nested groups in `use` declarations + +If you have a complex module tree with many different submodules and you need +to import a few items from each one, it might be useful to group all the +imports in the same declaration to keep your code clean and avoid repeating the +base modules’ name. + +The `use` declaration supports nesting to help you in those cases, both with +simple imports and glob ones. For example this snippets imports `bar`, `Foo`, +all the items in `baz` and `Bar`: + +```rust +# #![allow(unused_imports, dead_code)] +# +# mod foo { +# pub mod bar { +# pub type Foo = (); +# } +# pub mod baz { +# pub mod quux { +# pub type Bar = (); +# } +# } +# } +# +use foo::{ + bar::{self, Foo}, + baz::{*, quux::Bar}, +}; +# +# fn main() {} +``` + ### Bringing All Names into Scope with a Glob To bring all the items in a namespace into scope at once, we can use the `*` diff --git a/src/doc/book/2018-edition/src/ch08-01-vectors.md b/src/doc/book/2018-edition/src/ch08-01-vectors.md index 6452b42a82..66558dfc04 100644 --- a/src/doc/book/2018-edition/src/ch08-01-vectors.md +++ b/src/doc/book/2018-edition/src/ch08-01-vectors.md @@ -96,17 +96,32 @@ read their contents is a good next step. There are two ways to reference a value stored in a vector. In the examples, we’ve annotated the types of the values that are returned from these functions for extra clarity. -Listing 8-5 shows both methods of accessing a value in a vector, either with -indexing syntax or the `get` method: +Listing 8-5 shows the method of accessing a value in a vector with +indexing syntax: ```rust let v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; -let third: Option<&i32> = v.get(2); ``` -Listing 8-5: Using indexing syntax or the `get` method to +Listing 8-5: Using indexing syntax to +access an item in a vector + +Listing 8-6 shows the method of accessing a value in a vector, with +the `get` method: + +```rust +let v = vec![1, 2, 3, 4, 5]; +let v_index = 2; + +match v.get(v_index) { + Some(_) => { println!("Reachable element at index: {}", v_index); }, + None => { println!("Unreachable element at index: {}", v_index); } +} +``` + +Listing 8-6: Using the `get` method to access an item in a vector Note two details here. First, we use the index value of `2` to get the third @@ -119,7 +134,7 @@ Rust has two ways to reference an element so you can choose how the program behaves when you try to use an index value that the vector doesn’t have an element for. As an example, let’s see what a program will do if it has a vector that holds five elements and then tries to access an element at index 100, as -shown in Listing 8-6: +shown in Listing 8-7: ```rust,should_panic let v = vec![1, 2, 3, 4, 5]; @@ -128,7 +143,7 @@ let does_not_exist = &v[100]; let does_not_exist = v.get(100); ``` -Listing 8-6: Attempting to access the element at index +Listing 8-7: Attempting to access the element at index 100 in a vector containing five elements When we run this code, the first `[]` method will cause the program to panic @@ -150,7 +165,7 @@ When the program has a valid reference, the borrow checker enforces the ownership and borrowing rules (covered in Chapter 4) to ensure this reference and any other references to the contents of the vector remain valid. Recall the rule that states you can’t have mutable and immutable references in the same -scope. That rule applies in Listing 8-7, where we hold an immutable reference to +scope. That rule applies in Listing 8-8, where we hold an immutable reference to the first element in a vector and try to add an element to the end, which won’t work: @@ -162,7 +177,7 @@ let first = &v[0]; v.push(6); ``` -Listing 8-7: Attempting to add an element to a vector +Listing 8-8: Attempting to add an element to a vector while holding a reference to an item Compiling this code will result in this error: @@ -181,7 +196,7 @@ error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immuta | - immutable borrow ends here ``` -The code in Listing 8-7 might look like it should work: why should a reference +The code in Listing 8-8 might look like it should work: why should a reference to the first element care about what changes at the end of the vector? This error is due to the way vectors work: adding a new element onto the end of the vector might require allocating new memory and copying the old elements to the @@ -197,7 +212,7 @@ programs from ending up in that situation. If we want to access each element in a vector in turn, we can iterate through all of the elements rather than use indexes to access one at a time. Listing -8-8 shows how to use a `for` loop to get immutable references to each element +8-9 shows how to use a `for` loop to get immutable references to each element in a vector of `i32` values and print them: ```rust @@ -207,11 +222,11 @@ for i in &v { } ``` -Listing 8-8: Printing each element in a vector by +Listing 8-9: Printing each element in a vector by iterating over the elements using a `for` loop We can also iterate over mutable references to each element in a mutable vector -in order to make changes to all the elements. The `for` loop in Listing 8-9 +in order to make changes to all the elements. The `for` loop in Listing 8-10 will add `50` to each element: ```rust @@ -221,12 +236,12 @@ for i in &mut v { } ``` -Listing 8-9: Iterating over mutable references to +Listing 8-10: Iterating over mutable references to elements in a vector To change the value that the mutable reference refers to, we have to use the dereference operator (`*`) to get to the value in `i` before we can use the -`+=` operator . +`+=` operator . We'll talk more about `*` in Chapter 15. ### Using an Enum to Store Multiple Types @@ -241,7 +256,7 @@ some of the columns in the row contain integers, some floating-point numbers, and some strings. We can define an enum whose variants will hold the different value types, and then all the enum variants will be considered the same type: that of the enum. Then we can create a vector that holds that enum and so, -ultimately, holds different types. We’ve demonstrated this in Listing 8-10: +ultimately, holds different types. We’ve demonstrated this in Listing 8-11: ```rust enum SpreadsheetCell { @@ -257,7 +272,7 @@ let row = vec![ ]; ``` -Listing 8-10: Defining an `enum` to store values of +Listing 8-11: Defining an `enum` to store values of different types in one vector Rust needs to know what types will be in the vector at compile time so it knows diff --git a/src/doc/book/2018-edition/src/ch09-02-recoverable-errors-with-result.md b/src/doc/book/2018-edition/src/ch09-02-recoverable-errors-with-result.md index 9398b2787a..a36ebaf9ed 100644 --- a/src/doc/book/2018-edition/src/ch09-02-recoverable-errors-with-result.md +++ b/src/doc/book/2018-edition/src/ch09-02-recoverable-errors-with-result.md @@ -307,19 +307,22 @@ fn read_username_from_file() -> Result { Listing 9-6: A function that returns errors to the calling code using `match` -Let’s look at the return type of the function first: `Result`. This means the function is returning a value of the type -`Result` where the generic parameter `T` has been filled in with the -concrete type `String`, and the generic type `E` has been filled in with the -concrete type `io::Error`. If this function succeeds without any problems, the -code that calls this function will receive an `Ok` value that holds a -`String`—the username that this function read from the file. If this function -encounters any problems, the code that calls this function will receive an -`Err` value that holds an instance of `io::Error` that contains more -information about what the problems were. We chose `io::Error` as the return -type of this function because that happens to be the type of the error value -returned from both of the operations we’re calling in this function’s body that -might fail: the `File::open` function and the `read_to_string` method. +This function can be written in a much shorter way, but we're going to start by +doing a lot of it manually in order to explore error handling; at the end, +we'll show the easy way. Let’s look at the return type of the function first: +`Result`. This means the function is returning a value of +the type `Result` where the generic parameter `T` has been filled in +with the concrete type `String`, and the generic type `E` has been filled in +with the concrete type `io::Error`. If this function succeeds without any +problems, the code that calls this function will receive an `Ok` value that +holds a `String`—the username that this function read from the file. If this +function encounters any problems, the code that calls this function will +receive an `Err` value that holds an instance of `io::Error` that contains +more information about what the problems were. We chose `io::Error` as the +return type of this function because that happens to be the type of the error +value returned from both of the operations we’re calling in this function’s +body that might fail: the `File::open` function and the `read_to_string` +method. The body of the function starts by calling the `File::open` function. Then we handle the `Result` value returned with a `match` similar to the `match` in @@ -379,12 +382,12 @@ The `?` placed after a `Result` value is defined to work in almost the same way as the `match` expressions we defined to handle the `Result` values in Listing 9-6. If the value of the `Result` is an `Ok`, the value inside the `Ok` will get returned from this expression, and the program will continue. If the value -is an `Err`, the value inside the `Err` will be returned from the whole -function as if we had used the `return` keyword so the error value gets -propagated to the calling code. +is an `Err`, the `Err` will be returned from the whole function as if we had +used the `return` keyword so the error value gets propagated to the calling +code. There is a difference between what the `match` expression from Listing 9-6 and -`?` do: error values used with `?` go through the `from` function, defined in +`?` do: error values taken by `?` go through the `from` function, defined in the `From` trait in the standard library, which is used to convert errors from one type into another. When `?` calls the `from` function, the error type received is converted into the error type defined in the return type of the @@ -431,6 +434,30 @@ username in `s` when both `File::open` and `read_to_string` succeed rather than returning errors. The functionality is again the same as in Listing 9-6 and Listing 9-7; this is just a different, more ergonomic way to write it. +Speaking of different ways to write this function, there's a way to make this even +shorter: + +Filename: src/main.rs + +```rust +use std::io; +use std::io::Read; +use std::fs; + +fn read_username_from_file() -> Result { + fs::read_to_string("hello.txt") +} +``` + +Listing 9-9: Using `fs::read_to_string` + +Reading a file into a string is a fairly common operation, and so Rust +provides a convenience function called `fs::read_to_string` that will +open the file, create a new `String`, read the contents of the file, +and put the contents into that `String`, and then return it. Of course, +this doesn't give us the opportunity to show off all of this error handling, +so we did it the hard way at first. + #### The `?` Operator Can Only Be Used in Functions That Return `Result` The `?` operator can only be used in functions that have a return type of diff --git a/src/doc/book/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md b/src/doc/book/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md index 0563684b57..0d4cec876b 100644 --- a/src/doc/book/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md +++ b/src/doc/book/2018-edition/src/ch09-03-to-panic-or-not-to-panic.md @@ -192,7 +192,7 @@ impl Guess { } ``` -Listing 9-9: A `Guess` type that will only continue with +Listing 9-10: A `Guess` type that will only continue with values between 1 and 100 First, we define a struct named `Guess` that has a field named `value` that diff --git a/src/doc/book/2018-edition/src/ch10-00-generics.md b/src/doc/book/2018-edition/src/ch10-00-generics.md index 387ad9464c..3c52723224 100644 --- a/src/doc/book/2018-edition/src/ch10-00-generics.md +++ b/src/doc/book/2018-edition/src/ch10-00-generics.md @@ -15,11 +15,11 @@ explore how to define your own types, functions, and methods with generics! First, we’ll review how to extract a function to reduce code duplication. Next, we’ll use the same technique to make a generic function from two functions that -only differ in the types of their parameters. We’ll also explain how to use +differ only in the types of their parameters. We’ll also explain how to use generic types in struct and enum definitions. Then you’ll learn how to use *traits* to define behavior in a generic way. You -can then combine traits with generic types to constrain a generic type to only +can combine traits with generic types to constrain a generic type to only those types that have a particular behavior, as opposed to just any type. Finally, we’ll discuss *lifetimes*, a variety of generics that give the @@ -36,7 +36,7 @@ you recognize duplicated code to extract into a function, you’ll start to recognize duplicated code that can use generics. Consider a short program that finds the largest number in a list, as shown in -Listing 10-1: +Listing 10-1. Filename: src/main.rs @@ -65,13 +65,13 @@ the first number in the list in a variable named `largest`. Then it iterates through all the numbers in the list, and if the current number is greater than the number stored in `largest`, it replaces the number in that variable. However, if the current number is less than the largest number seen so far, the -variable doesn’t change and the code moves on to the next number in the list. +variable doesn’t change, and the code moves on to the next number in the list. After considering all the numbers in the list, `largest` should hold the largest number, which in this case is 100. To find the largest number in two different lists of numbers, we can duplicate the code in Listing 10-1 and use the same logic at two different places in the -program, as shown in Listing 10-2: +program, as shown in Listing 10-2. Filename: src/main.rs @@ -107,7 +107,7 @@ fn main() { lists of numbers Although this code works, duplicating code is tedious and error prone. We also -have to update the code in multiple places to change it. +have to update the code in multiple places when we want to change it. To eliminate this duplication, we can create an abstraction by defining a function that operates on any list of integers given to it in a parameter. This @@ -117,7 +117,7 @@ largest number in a list abstractly. In Listing 10-3, we extracted the code that finds the largest number into a function named `largest`. Unlike the code in Listing 10-1, which can find the largest number in only one particular list, this program can find the largest -number in two different lists: +number in two different lists. Filename: src/main.rs @@ -161,7 +161,7 @@ In sum, here are the steps we took to change the code from Listing 10-2 to Listing 10-3: 1. Identify duplicate code. -2. Extract the duplicate code into the body of the function, and specify the +2. Extract the duplicate code into the body of the function and specify the inputs and return values of that code in the function signature. 3. Update the two instances of duplicated code to call the function instead. diff --git a/src/doc/book/2018-edition/src/ch10-01-syntax.md b/src/doc/book/2018-edition/src/ch10-01-syntax.md index 1c6bd1bd32..9c8fd4fcbf 100644 --- a/src/doc/book/2018-edition/src/ch10-01-syntax.md +++ b/src/doc/book/2018-edition/src/ch10-01-syntax.md @@ -13,7 +13,7 @@ parameters and return value. Doing so makes our code more flexible and provides more functionality to callers of our function while preventing code duplication. Continuing with our `largest` function, Listing 10-4 shows two functions that -both find the largest value in a slice: +both find the largest value in a slice. Filename: src/main.rs @@ -66,17 +66,17 @@ the largest `i32` in a slice. The `largest_char` function finds the largest the duplication by introducing a generic type parameter in a single function. To parameterize the types in the new function we’ll define, we need to name the -type parameter, just like we do for the value parameters to a function. You can +type parameter, just as we do for the value parameters to a function. You can use any identifier as a type parameter name. But we’ll use `T` because, by convention, parameter names in Rust are short, often just a letter, and Rust’s -type naming convention is CamelCase. Short for “type,” `T` is the default +type-naming convention is CamelCase. Short for “type,” `T` is the default choice of most Rust programmers. When we use a parameter in the body of the function, we have to declare the -parameter name in the signature so that the compiler knows what that name -means. Similarly, when we use a type parameter name in a function signature, we -have to declare the type parameter name before we use it. To define the generic -`largest` function, place type name declarations inside angle brackets (`<>`) +parameter name in the signature so the compiler knows what that name means. +Similarly, when we use a type parameter name in a function signature, we have +to declare the type parameter name before we use it. To define the generic +`largest` function, place type name declarations inside angle brackets, `<>`, between the name of the function and the parameter list, like this: ```rust,ignore @@ -140,16 +140,16 @@ traits in the next section. For now, this error states that the body of `largest` won’t work for all possible types that `T` could be. Because we want to compare values of type `T` in the body, we can only use types whose values can be ordered. To enable comparisons, the standard library has the -`std::cmp::PartialOrd` trait that you can implement on types (see Appendix C, -“Derivable Traits,” for more on this trait). You’ll learn how to specify that a -generic type has a particular trait in the “Trait Bounds” section, but let’s -first explore other ways of using generic type parameters. +`std::cmp::PartialOrd` trait that you can implement on types (see Appendix C +for more on this trait). You’ll learn how to specify that a generic type has a +particular trait in the “Trait Bounds” section, but let’s first explore other +ways of using generic type parameters. ### In Struct Definitions We can also define structs to use a generic type parameter in one or more fields using the `<>` syntax. Listing 10-6 shows how to define a `Point` -struct to hold `x` and `y` coordinate values of any type: +struct to hold `x` and `y` coordinate values of any type. Filename: src/main.rs @@ -174,11 +174,11 @@ angle brackets just after the name of the struct. Then we can use the generic type in the struct definition where we would otherwise specify concrete data types. -Note that because we’ve only used one generic type to define `Point`, this +Note that because we’ve used only one generic type to define `Point`, this definition says that the `Point` struct is generic over some type `T`, and the fields `x` and `y` are *both* that same type, whatever that type may be. If we create an instance of a `Point` that has values of different types, as in -Listing 10-7, our code won’t compile: +Listing 10-7, our code won’t compile. Filename: src/main.rs @@ -194,11 +194,11 @@ fn main() { ``` Listing 10-7: The fields `x` and `y` must be the same -type because both have the same generic data type `T` +type because both have the same generic data type `T`. -In this example, when we assign the integer value `5` to `x`, we let the +In this example, when we assign the integer value 5 to `x`, we let the compiler know that the generic type `T` will be an integer for this instance of -`Point`. Then when we specify `4.0` for `y`, which we’ve defined to have the +`Point`. Then when we specify 4.0 for `y`, which we’ve defined to have the same type as `x`, we’ll get a type mismatch error like this: ```text @@ -216,7 +216,7 @@ floating-point variable To define a `Point` struct where `x` and `y` are both generics but could have different types, we can use multiple generic type parameters. For example, in Listing 10-8, we can change the definition of `Point` to be generic over types -`T` and `U` where `x` is of type `T` and `y` is of type `U`: +`T` and `U` where `x` is of type `T` and `y` is of type `U`. Filename: src/main.rs @@ -245,7 +245,7 @@ could indicate that your code needs restructuring into smaller pieces. As we did with structs, we can define enums to hold generic data types in their variants. Let’s take another look at the `Option` enum that the standard -library provides that we used in Chapter 6: +library provides, which we used in Chapter 6: ```rust enum Option { @@ -276,7 +276,7 @@ The `Result` enum is generic over two types, `T` and `E`, and has two variants: `E`. This definition makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (return a value of some type `T`) or fail (return an error of some type `E`). In fact, this is what we used to open a -file in Listing 9-3 where `T` was filled in with the type `std::fs::File` when +file in Listing 9-3, where `T` was filled in with the type `std::fs::File` when the file was opened successfully and `E` was filled in with the type `std::io::Error` when there were problems opening the file. @@ -286,9 +286,9 @@ avoid duplication by using generic types instead. ### In Method Definitions -As we did in Chapter 5, we can implement methods on structs and enums that have -generic types in their definitions. Listing 10-9 shows the `Point` struct we -defined in Listing 10-6 with a method named `x` implemented on it: +We can implement methods on structs and enums (as we did in Chapter 5) and use +generic types in their definitions, too. Listing 10-9 shows the `Point` +struct we defined in Listing 10-6 with a method named `x` implemented on it. Filename: src/main.rs @@ -325,7 +325,7 @@ brackets in `Point` is a generic type rather than a concrete type. We could, for example, implement methods only on `Point` instances rather than on `Point` instances with any generic type. In Listing 10-10 we use the -concrete type `f32`, meaning we don’t declare any types after `impl`: +concrete type `f32`, meaning we don’t declare any types after `impl`. ```rust # struct Point { @@ -344,10 +344,10 @@ impl Point { struct with a particular concrete type for the generic type parameter `T` This code means the type `Point` will have a method named -`distance_from_origin`, and other instances of `Point` where `T` is not of +`distance_from_origin` and other instances of `Point` where `T` is not of type `f32` will not have this method defined. The method measures how far our point is from the point at coordinates (0.0, 0.0) and uses mathematical -operations that are only available for floating point types. +operations that are available only for floating point types. Generic type parameters in a struct definition aren’t always the same as those you use in that struct’s method signatures. For example, Listing 10-11 defines @@ -355,7 +355,7 @@ the method `mixup` on the `Point` struct from Listing 10-8. The method takes another `Point` as a parameter, which might have different types than the `self` `Point` we’re calling `mixup` on. The method creates a new `Point` instance with the `x` value from the `self` `Point` (of type `T`) and the `y` -value from the passed-in `Point` (of type `W`): +value from the passed-in `Point` (of type `W`). Filename: src/main.rs @@ -427,8 +427,8 @@ let float = Some(5.0); ``` When Rust compiles this code, it performs monomorphization. During that -process, the compiler reads the values that have been used in the instances of -`Option` and identifies two kinds of `Option`: one is `i32` and the other +process, the compiler reads the values that have been used in `Option` +instances and identifies two kinds of `Option`: one is `i32` and the other is `f64`. As such, it expands the generic definition of `Option` into `Option_i32` and `Option_f64`, thereby replacing the generic definition with the specific ones. @@ -457,6 +457,6 @@ fn main() { Because Rust compiles generic code into code that specifies the type in each instance, we pay no runtime cost for using generics. When the code runs, it -performs just like it would if we had duplicated each definition by hand. The +performs just as it would if we had duplicated each definition by hand. The process of monomorphization makes Rust’s generics extremely efficient at runtime. diff --git a/src/doc/book/2018-edition/src/ch10-02-traits.md b/src/doc/book/2018-edition/src/ch10-02-traits.md index e58ac981c0..7bc1caaf1c 100644 --- a/src/doc/book/2018-edition/src/ch10-02-traits.md +++ b/src/doc/book/2018-edition/src/ch10-02-traits.md @@ -25,7 +25,7 @@ We want to make a media aggregator library that can display summaries of data that might be stored in a `NewsArticle` or `Tweet` instance. To do this, we need a summary from each type, and we need to request that summary by calling a `summarize` method on an instance. Listing 10-12 shows the definition of a -`Summary` trait that expresses this behavior: +`Summary` trait that expresses this behavior. Filename: src/lib.rs @@ -39,7 +39,7 @@ pub trait Summary { behavior provided by a `summarize` method Here, we declare a trait using the `trait` keyword and then the trait’s name, -which is `Summary` in this case. Inside the curly brackets we declare the +which is `Summary` in this case. Inside the curly brackets, we declare the method signatures that describe the behaviors of the types that implement this trait, which in this case is `fn summarize(&self) -> String`. @@ -127,14 +127,14 @@ know, people`. Note that because we defined the `Summary` trait and the `NewsArticle` and `Tweet` types in the same *lib.rs* in Listing 10-13, they’re all in the same -scope. Let’s say this *lib.rs* is for a crate we’ve called `aggregator`, and +scope. Let’s say this *lib.rs* is for a crate we’ve called `aggregator` and someone else wants to use our crate’s functionality to implement the `Summary` trait on a struct defined within their library’s scope. They would need to import the trait into their scope first. They would do so by specifying `use -aggregator::Summary;`, which then enables them to implement `Summary` for their -type. The `Summary` trait would also need to be a public trait for another -crate to implement it, which it is because we put the `pub` keyword before -`trait` in Listing 10-12. +aggregator::Summary;`, which then would enable them to implement `Summary` for +their type. The `Summary` trait would also need to be a public trait for +another crate to implement it, which it is because we put the `pub` keyword +before `trait` in Listing 10-12. One restriction to note with trait implementations is that we can implement a trait on a type only if either the trait or the type is local to our crate. @@ -162,8 +162,8 @@ Then, as we implement the trait on a particular type, we can keep or override each method’s default behavior. Listing 10-14 shows how to specify a default string for the `summarize` method -of the `Summary` trait instead of only defining the method signature, like we -did in Listing 10-12: +of the `Summary` trait instead of only defining the method signature, as we did +in Listing 10-12. Filename: src/lib.rs @@ -258,20 +258,29 @@ This code prints `1 new tweet: (Read more from @horse_ebooks...)`. Note that it isn’t possible to call the default implementation from an overriding implementation of that same method. -### Trait Bounds +### Traits as arguments Now that you know how to define traits and implement those traits on types, we -can explore how to use traits with generic type parameters. We can use *trait -bounds* to constrain generic types to ensure the type will be limited to those -that implement a particular trait and behavior. +can explore how to use traits to accept arguments of many different types. For example, in Listing 10-13, we implemented the `Summary` trait on the types `NewsArticle` and `Tweet`. We can define a function `notify` that calls the -`summarize` method on its parameter `item`, which is of the generic type `T`. -To be able to call `summarize` on `item` without getting an error telling us -that the generic type `T` doesn’t implement the method `summarize`, we can use -trait bounds on `T` to specify that `item` must be of a type that implements -the `Summary` trait: +`summarize` method on its parameter `item`, which is of some type that implements +the `Summary` trait. To do this, we can use the '`impl Trait`' syntax, like this: + +```rust,ignore +pub fn notify(item: impl Summary) { + println!("Breaking news! {}", item.summarize()); +} +``` + +In the body of `notify`, we can call any methods on `item` that come from +the `Summary` trait, like `summarize`. + +#### Trait Bounds + +The `impl Trait` syntax works for short examples, but is syntax sugar for a +longer form. This is called a 'trait bound', and it looks like this: ```rust,ignore pub fn notify(item: T) { @@ -279,28 +288,45 @@ pub fn notify(item: T) { } ``` -We place trait bounds with the declaration of the generic type parameter, after -a colon and inside angle brackets. Because of the trait bound on `T`, we can +This is equivalent to the example above, but is a bit more verbose. We place +trait bounds with the declaration of the generic type parameter, after a +colon and inside angle brackets. Because of the trait bound on `T`, we can call `notify` and pass in any instance of `NewsArticle` or `Tweet`. Code that calls the function with any other type, like a `String` or an `i32`, won’t compile, because those types don’t implement `Summary`. +When should you use this form over `impl Trait`? While `impl Trait` is nice for +shorter examples, trait bounds are nice for more complex ones. For example, +say we wanted to take two things that implement `Summary`: + +```rust,ignore +pub fn notify(item1: impl Summary, item2: impl Summary) { +pub fn notify(item1: T, item2: T) { +``` + +The version with the bound is a bit easier. In general, you should use whatever +form makes your code the most understandable. + +##### Multiple trait bounds with `+` + We can specify multiple trait bounds on a generic type using the `+` syntax. For example, to use display formatting on the type `T` in a function as well as the `summarize` method, we can use `T: Summary + Display` to say `T` can be any -type that implements `Summary` and `Display`. - -However, there are downsides to using too many trait bounds. Each generic has -its own trait bounds; so functions with multiple generic type parameters can -have lots of trait bound information between a function’s name and its -parameter list, making the function signature hard to read. For this reason, -Rust has alternate syntax for specifying trait bounds inside a `where` clause -after the function signature. So instead of writing this: +type that implements `Summary` and `Display`. This can grow quite complex! ```rust,ignore fn some_function(t: T, u: U) -> i32 { ``` +#### `where` clauses for clearer code + +However, there are downsides to using too many trait bounds. Each generic has +its own trait bounds, so functions with multiple generic type parameters can +have lots of trait bound information between a function’s name and its +parameter list, making the function signature hard to read. For this reason, +Rust has alternate syntax for specifying trait bounds inside a `where` clause +after the function signature. So instead of writing this: + we can use a `where` clause, like this: ```rust,ignore @@ -314,6 +340,60 @@ This function’s signature is less cluttered in that the function name, parameter list, and return type are close together, similar to a function without lots of trait bounds. +### Returning Traits + +We can use the `impl Trait` syntax in return position as well, to return +something that implements a trait: + +```rust,ignore +fn returns_summarizable() -> impl Summary { + Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + reply: false, + retweet: false, + } +} +``` + +This signature says, "I'm going to return something that implements the +`Summary` trait, but I'm not going to tell you the exact type. In our case, +we're returning a `Tweet`, but the caller doesn't know that. + +Why is this useful? In chapter 13, we're going to learn about two features +that rely heavily on traits: closures, and iterators. These features create +types that only the compiler knows, or types that are very, very long. +`impl Trait` lets you simply say "this returns an `Iterator`" without +needing to write out a really long type. + +This only works if you have a single type that you're returning, however. +For example, this would *not* work: + +```rust,ignore +fn returns_summarizable(switch: bool) -> impl Summary { + if switch { + NewsArticle { + headline: String::from("Penguins win the Stanley Cup Championship!"), + location: String::from("Pittsburgh, PA, USA"), + author: String::from("Iceburgh"), + content: String::from("The Pittsburgh Penguins once again are the best + hockey team in the NHL."), + } + } else { + Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + reply: false, + retweet: false, + } + } +} +``` + +Here, we try to return either a `NewsArticle` or a `Tweet`. This cannot work, +due to restrictions around how `impl Trait` works. To write this code, you'll +have to wait until Chapter 17, "trait objects". + ### Fixing the `largest` Function with Trait Bounds Now that you know how to specify the behavior you want to use using the generic @@ -332,7 +412,7 @@ error[E0369]: binary operation `>` cannot be applied to type `T` ``` In the body of `largest` we wanted to compare two values of type `T` using the -greater-than (`>`) operator. Because that operator is defined as a default +greater than (`>`) operator. Because that operator is defined as a default method on the standard library trait `std::cmp::PartialOrd`, we need to specify `PartialOrd` in the trait bounds for `T` so the `largest` function can work on slices of any type that we can compare. We don’t need to bring `PartialOrd` @@ -379,7 +459,7 @@ To call this code with only those types that implement the `Copy` trait, we can add `Copy` to the trait bounds of `T`! Listing 10-15 shows the complete code of a generic `largest` function that will compile as long as the types of the values in the slice that we pass into the function implement the `PartialOrd` -*and* `Copy` traits, like `i32` and `char` do: +*and* `Copy` traits, like `i32` and `char` do. Filename: src/main.rs @@ -434,7 +514,7 @@ we can implement methods conditionally for types that implement the specified traits. For example, the type `Pair` in Listing 10-16 always implements the `new` function. But `Pair` only implements the `cmp_display` method if its inner type `T` implements the `PartialOrd` trait that enables comparison *and* -the `Display` trait that enables printing: +the `Display` trait that enables printing. ```rust use std::fmt::Display; diff --git a/src/doc/book/2018-edition/src/ch10-03-lifetime-syntax.md b/src/doc/book/2018-edition/src/ch10-03-lifetime-syntax.md index 7fd80971bc..6e4a8924f3 100644 --- a/src/doc/book/2018-edition/src/ch10-03-lifetime-syntax.md +++ b/src/doc/book/2018-edition/src/ch10-03-lifetime-syntax.md @@ -2,8 +2,8 @@ One detail we didn’t discuss in the “References and Borrowing” section in Chapter 4 is that every reference in Rust has a *lifetime*, which is the scope -for which that reference is valid. Most of the time lifetimes are implicit and -inferred, just like most of the time types are inferred. We must annotate types +for which that reference is valid. Most of the time, lifetimes are implicit and +inferred, just like most of the time, types are inferred. We must annotate types when multiple types are possible. In a similar way, we must annotate lifetimes when the lifetimes of references could be related in a few different ways. Rust requires us to annotate the relationships using generic lifetime parameters to @@ -16,12 +16,12 @@ common ways you might encounter lifetime syntax so you can become familiar with the concepts. See the “Advanced Lifetimes” section in Chapter 19 for more detailed information. -### Lifetimes Prevent Dangling References +### Preventing Dangling References with Lifetimes The main aim of lifetimes is to prevent dangling references, which cause a program to reference data other than the data it’s intended to reference. Consider the program in Listing 10-17, which has an outer scope and an inner -scope: +scope. ```rust,ignore { @@ -39,15 +39,15 @@ scope: Listing 10-17: An attempt to use a reference whose value has gone out of scope -> Note: The example in Listing 10-17 and the next few examples declare -> variables without giving them an initial value, so the variable name exists -> in the outer scope. At first glance, this might appear to be in conflict with -> Rust having no null values. However, if we try to use a variable before -> giving it a value, we’ll get a compile time error, which shows that Rust -> indeed does not allow null values. +> Note: The examples in Listings 10-17, 10-18, and 10-24 declare variables +> without giving them an initial value, so the variable name exists in the +> outer scope. At first glance, this might appear to be in conflict with Rust’s +> having no null values. However, if we try to use a variable before giving it +> a value, we’ll get a compile-time error, which shows that Rust indeed does +> not allow null values. The outer scope declares a variable named `r` with no initial value, and the -inner scope declares a variable named `x` with the initial value of `5`. Inside +inner scope declares a variable named `x` with the initial value of 5. Inside the inner scope, we attempt to set the value of `r` as a reference to `x`. Then the inner scope ends, and we attempt to print the value in `r`. This code won’t compile because the value `r` is referring to has gone out of scope before we @@ -76,9 +76,9 @@ It uses a borrow checker. ### The Borrow Checker -The Rust compiler has a *borrow checker* that compares scopes to determine that -all borrows are valid. Listing 10-18 shows the same code as Listing 10-17 but -with annotations showing the lifetimes of the variables: +The Rust compiler has a *borrow checker* that compares scopes to determine +whether all borrows are valid. Listing 10-18 shows the same code as Listing +10-17 but with annotations showing the lifetimes of the variables. ```rust,ignore { @@ -104,7 +104,7 @@ with a lifetime of `'b`. The program is rejected because `'b` is shorter than `'a`: the subject of the reference doesn’t live as long as the reference. Listing 10-19 fixes the code so it doesn’t have a dangling reference and -compiles without any errors: +compiles without any errors. ```rust { @@ -133,7 +133,7 @@ lifetimes of parameters and return values in the context of functions. Let’s write a function that returns the longer of two string slices. This function will take two string slices and return a string slice. After we’ve implemented the `longest` function, the code in Listing 10-20 should print `The -longest string is abcd`: +longest string is abcd`. Filename: src/main.rs @@ -148,7 +148,7 @@ fn main() { ``` Listing 10-20: A `main` function that calls the `longest` -function to find the longest of two string slices +function to find the longer of two string slices Note that we want the function to take string slices, which are references, because we don’t want the `longest` function to take ownership of its @@ -161,7 +161,7 @@ discussion about why the parameters we use in Listing 10-20 are the ones we want. If we try to implement the `longest` function as shown in Listing 10-21, it -won’t compile: +won’t compile. Filename: src/main.rs @@ -201,8 +201,8 @@ reference to `y`! When we’re defining this function, we don’t know the concrete values that will be passed into this function, so we don’t know whether the `if` case or the `else` case will execute. We also don’t know the concrete lifetimes of the -references that will be passed in, so we can’t look at the scopes like we did -in Listings 10-18 and 10-19 to determine that the reference we return will +references that will be passed in, so we can’t look at the scopes as we did in +Listings 10-18 and 10-19 to determine whether the reference we return will always be valid. The borrow checker can’t determine this either, because it doesn’t know how the lifetimes of `x` and `y` relate to the lifetime of the return value. To fix this error, we’ll add generic lifetime parameters that @@ -212,14 +212,14 @@ perform its analysis. ### Lifetime Annotation Syntax Lifetime annotations don’t change how long any of the references live. Just -like functions can accept any type when the signature specifies a generic type +as functions can accept any type when the signature specifies a generic type parameter, functions can accept references with any lifetime by specifying a generic lifetime parameter. Lifetime annotations describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes. Lifetime annotations have a slightly unusual syntax: the names of lifetime -parameters must start with an apostrophe `'` and are usually all lowercase and +parameters must start with an apostrophe (`'`) and are usually all lowercase and very short, like generic types. Most people use the name `'a`. We place lifetime parameter annotations after the `&` of a reference, using a space to separate the annotation from the reference’s type. @@ -234,7 +234,7 @@ reference to an `i32` that also has the lifetime `'a`. &'a mut i32 // a mutable reference with an explicit lifetime ``` -One lifetime annotation by itself doesn’t have much meaning because the +One lifetime annotation by itself doesn’t have much meaning, because the annotations are meant to tell Rust how generic lifetime parameters of multiple references relate to each other. For example, let’s say we have a function with the parameter `first` that is a reference to an `i32` with lifetime `'a`. The @@ -250,8 +250,8 @@ function. As with generic type parameters, we need to declare generic lifetime parameters inside angle brackets between the function name and the parameter list. The constraint we want to express in this signature is that all the references in the parameters and the return value must have the same lifetime. -We’ll name the lifetime `'a`, and then add it to each reference, as shown in -Listing 10-22: +We’ll name the lifetime `'a` and then add it to each reference, as shown in +Listing 10-22. Filename: src/main.rs @@ -302,7 +302,7 @@ lifetimes of `x` and `y`. Let’s look at how the lifetime annotations restrict the `longest` function by passing in references that have different concrete lifetimes. Listing 10-23 is -a straightforward example: +a straightforward example. Filename: src/main.rs @@ -341,7 +341,7 @@ declaration of the `result` variable outside the inner scope but leave the assignment of the value to the `result` variable inside the scope with `string2`. Then we’ll move the `println!` that uses `result` outside the inner scope, after the inner scope has ended. The code in Listing 10-24 will not -compile: +compile. Filename: src/main.rs @@ -358,7 +358,7 @@ fn main() { ``` Listing 10-24: Attempting to use `result` after `string2` -has gone out of scope; the code won’t compile +has gone out of scope When we try to compile this code, we’ll get this error: @@ -381,7 +381,7 @@ this because we annotated the lifetimes of the function parameters and return values using the same lifetime parameter `'a`. As humans, we can look at this code and see that `string1` is longer than -`string2`, and therefore `result` will contain a reference to `string1`. +`string2` and therefore `result` will contain a reference to `string1`. Because `string1` has not gone out of scope yet, a reference to `string1` will still be valid for the `println!` statement. However, the compiler can’t see that the reference is valid in this case. We’ve told Rust that the lifetime of @@ -473,7 +473,7 @@ would create dangling pointers or otherwise violate memory safety. So far, we’ve only defined structs to hold owned types. It’s possible for structs to hold references, but in that case we would need to add a lifetime annotation on every reference in the struct’s definition. Listing 10-25 has a -struct named `ImportantExcerpt` that holds a string slice: +struct named `ImportantExcerpt` that holds a string slice. Filename: src/main.rs @@ -512,8 +512,8 @@ the `ImportantExcerpt` goes out of scope, so the reference in the You’ve learned that every reference has a lifetime and that you need to specify lifetime parameters for functions or structs that use references. However, in -Chapter 4 we had a function in the “String Slices” section, which is shown again -in Listing 10-26, that compiled without lifetime annotations: +Chapter 4 we had a function in Listing 4-9, which is shown again in Listing +10-26, that compiled without lifetime annotations. Filename: src/lib.rs @@ -531,7 +531,7 @@ fn first_word(s: &str) -> &str { } ``` -Listing 10-26: A function we defined in Chapter 4 that +Listing 10-26: A function we defined in Listing 4-9 that compiled without lifetime annotations, even though the parameter and return type are references @@ -548,8 +548,8 @@ After writing a lot of Rust code, the Rust team found that Rust programmers were entering the same lifetime annotations over and over in particular situations. These situations were predictable and followed a few deterministic patterns. The developers programmed these patterns into the compiler’s code so -the borrow checker could infer the lifetimes in these situations and not need -explicit annotations. +the borrow checker could infer the lifetimes in these situations and wouldn’t +need explicit annotations. This piece of Rust history is relevant because it’s possible that more deterministic patterns will emerge and be added to the compiler. In the future, @@ -601,7 +601,8 @@ fn first_word(s: &str) -> &str { ``` Then the compiler applies the first rule, which specifies that each parameter -gets its own lifetime. We’ll call it `'a` as usual, so now the signature is: +gets its own lifetime. We’ll call it `'a` as usual, so now the signature is +this: ```rust,ignore fn first_word<'a>(s: &'a str) -> &str { @@ -705,8 +706,11 @@ and all lifetimes have been accounted for. One special lifetime we need to discuss is `'static`, which denotes the entire duration of the program. All string literals have the `'static` lifetime, which -we can annotate as follows: `let s: &'static str = "I have a static -lifetime.";`. +we can annotate as follows: + +```rust +let s: &'static str = "I have a static lifetime."; +``` The text of this string is stored directly in the binary of your program, which is always available. Therefore, the lifetime of all string literals is @@ -763,6 +767,5 @@ analysis happens at compile time, which doesn’t affect runtime performance! Believe it or not, there is much more to learn on the topics we discussed in this chapter: Chapter 17 discusses trait objects, which are another way to use traits. Chapter 19 covers more complex scenarios involving lifetime annotations -as well as some advanced type system features. But in the next chapter, you’ll -learn how to write tests in Rust so you can make sure your code is working the -way it should. +as well as some advanced type system features. But next, you’ll learn how to +write tests in Rust so you can make sure your code is working the way it should. diff --git a/src/doc/book/2018-edition/src/ch12-01-accepting-command-line-arguments.md b/src/doc/book/2018-edition/src/ch12-01-accepting-command-line-arguments.md index f013eea800..71c1ae303a 100644 --- a/src/doc/book/2018-edition/src/ch12-01-accepting-command-line-arguments.md +++ b/src/doc/book/2018-edition/src/ch12-01-accepting-command-line-arguments.md @@ -5,7 +5,7 @@ Let’s create a new project with, as always, `cargo new`. We’ll call our proj on your system. ```text -$ cargo new --bin minigrep +$ cargo new minigrep Created binary (application) `minigrep` project $ cd minigrep ``` diff --git a/src/doc/book/2018-edition/src/ch12-02-reading-a-file.md b/src/doc/book/2018-edition/src/ch12-02-reading-a-file.md index 9e70465cb2..76e95a8b9f 100644 --- a/src/doc/book/2018-edition/src/ch12-02-reading-a-file.md +++ b/src/doc/book/2018-edition/src/ch12-02-reading-a-file.md @@ -32,7 +32,7 @@ shown in Listing 12-4: ```rust,should_panic use std::env; -use std::fs::File; +use std::fs; use std::io::prelude::*; fn main() { @@ -45,11 +45,8 @@ fn main() { // --snip-- println!("In file {}", filename); - let mut f = File::open(filename).expect("file not found"); - - let mut contents = String::new(); - f.read_to_string(&mut contents) - .expect("something went wrong reading the file"); + let contents = fs::read_to_string(filename) + .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); } @@ -59,22 +56,18 @@ fn main() { by the second argument First, we add some more `use` statements to bring in relevant parts of the -standard library: we need `std::fs::File` to handle files, and +standard library: we need `std::fs` to handle files, and `std::io::prelude::*` contains various useful traits for doing I/O, including file I/O. In the same way that Rust has a general prelude that brings certain -types and functions into scope automatically, the `std::io` module has its own -prelude of common types and functions you’ll need when working with I/O. Unlike -with the default prelude, we must explicitly add a `use` statement for the -prelude from `std::io`. +types and functions into scope automatically, the `std::io` module has its +own prelude of common types and functions you’ll need when working with I/O. +Unlike with the default prelude, we must explicitly add a `use` statement for +the prelude from `std::io`. -In `main`, we’ve added three statements: first, we get a mutable handle to the -file by calling the `File::open` function and passing it the value of the -`filename` variable. Second, we create a variable called `contents` and set it -to a mutable, empty `String`. This will hold the content of the file after we -read it in. Third, we call `read_to_string` on our file handle and pass a -mutable reference to `contents` as an argument. +In `main`, we’ve added a new statement: `fs::read_to_string` will take the +`filename`, open that file, and then produce a new `String` with its contents. -After those lines, we’ve again added a temporary `println!` statement that +After that lines, we’ve again added a temporary `println!` statement that prints the value of `contents` after the file is read, so we can check that the program is working so far. diff --git a/src/doc/book/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md b/src/doc/book/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md index 072400699d..0e19325a30 100644 --- a/src/doc/book/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/src/doc/book/2018-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -136,7 +136,7 @@ the struct fields rather than having separate variables: ```rust,should_panic # use std::env; -# use std::fs::File; +# use std::fs; # fn main() { let args: Vec = env::args().collect(); @@ -146,7 +146,8 @@ fn main() { println!("Searching for {}", config.query); println!("In file {}", config.filename); - let mut f = File::open(config.filename).expect("file not found"); + let contents = fs::read_to_string(config.filename) + .expect("Something went wrong reading the file"); // --snip-- } @@ -466,10 +467,7 @@ fn main() { } fn run(config: Config) { - let mut f = File::open(config.filename).expect("file not found"); - - let mut contents = String::new(); - f.read_to_string(&mut contents) + let contents = fs::read_to_string(config.filename) .expect("something went wrong reading the file"); println!("With text:\n{}", contents); @@ -502,11 +500,8 @@ use std::error::Error; // --snip-- -fn run(config: Config) -> Result<(), Box> { - let mut f = File::open(config.filename)?; - - let mut contents = String::new(); - f.read_to_string(&mut contents)?; +fn run(config: Config) -> Result<(), Box> { + let contents = fs::read_to_string(config.filename)?; println!("With text:\n{}", contents); @@ -518,19 +513,20 @@ fn run(config: Config) -> Result<(), Box> { `Result` We’ve made three significant changes here. First, we changed the return type of -the `run` function to `Result<(), Box>`. This function previously +the `run` function to `Result<(), Box>`. This function previously returned the unit type, `()`, and we keep that as the value returned in the `Ok` case. -For the error type, we used the *trait object* `Box` (and we’ve brought -`std::error::Error` into scope with a `use` statement at the top). We’ll cover -trait objects in Chapter 17. For now, just know that `Box` means the -function will return a type that implements the `Error` trait, but we don’t -have to specify what particular type the return value will be. This gives us -flexibility to return error values that may be of different types in different -error cases. +For the error type, we used the *trait object* `Box` (and we’ve +brought `std::error::Error` into scope with a `use` statement at the top). +We’ll cover trait objects in Chapter 17. For now, just know that `Box` means the function will return a type that implements the `Error` +trait, but we don’t have to specify what particular type the return value +will be. This gives us flexibility to return error values that may be of +different types in different error cases. This is what the `dyn` means, it's +short for "dynamic." -Second, we’ve removed the calls to `expect` in favor of `?`, as we talked about +Second, we’ve removed the call to `expect` in favor of `?`, as we talked about in Chapter 9. Rather than `panic!` on an error, `?` will return the error value from the current function for the caller to handle. @@ -625,7 +621,7 @@ impl Config { } } -pub fn run(config: Config) -> Result<(), Box> { +pub fn run(config: Config) -> Result<(), Box> { // --snip-- } ``` diff --git a/src/doc/book/2018-edition/src/ch12-04-testing-the-librarys-functionality.md b/src/doc/book/2018-edition/src/ch12-04-testing-the-librarys-functionality.md index 7bd761bc54..0f2b54523f 100644 --- a/src/doc/book/2018-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/src/doc/book/2018-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -276,11 +276,10 @@ will print each line returned from `search`: Filename: src/lib.rs ```rust,ignore -pub fn run(config: Config) -> Result<(), Box> { +pub fn run(config: Config) -> Result<(), Box> { let mut f = File::open(config.filename)?; - let mut contents = String::new(); - f.read_to_string(&mut contents)?; + let contents = fs::read_to_string(config.filename)?; for line in search(&config.query, &contents) { println!("{}", line); diff --git a/src/doc/book/2018-edition/src/ch12-05-working-with-environment-variables.md b/src/doc/book/2018-edition/src/ch12-05-working-with-environment-variables.md index 78a4713279..45f7e552ed 100644 --- a/src/doc/book/2018-edition/src/ch12-05-working-with-environment-variables.md +++ b/src/doc/book/2018-edition/src/ch12-05-working-with-environment-variables.md @@ -155,7 +155,7 @@ won’t compile yet: ```rust # use std::error::Error; -# use std::fs::File; +# use std::fs::{self, File}; # use std::io::prelude::*; # # fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { @@ -166,17 +166,14 @@ won’t compile yet: # vec![] # } # -# struct Config { +# pub struct Config { # query: String, # filename: String, # case_sensitive: bool, # } # -pub fn run(config: Config) -> Result<(), Box> { - let mut f = File::open(config.filename)?; - - let mut contents = String::new(); - f.read_to_string(&mut contents)?; +pub fn run(config: Config) -> Result<(), Box> { + let contents = fs::read_to_string(config.filename)?; let results = if config.case_sensitive { search(&config.query, &contents) diff --git a/src/doc/book/2018-edition/src/ch13-01-closures.md b/src/doc/book/2018-edition/src/ch13-01-closures.md index f13a60b2cf..a00273e066 100644 --- a/src/doc/book/2018-edition/src/ch13-01-closures.md +++ b/src/doc/book/2018-edition/src/ch13-01-closures.md @@ -469,10 +469,10 @@ closure we want to store in the `calculation` field must have one `u32` parameter (specified within the parentheses after `Fn`) and must return a `u32` (specified after the `->`). -> Note: Functions implement all three of the `Fn` traits too. If what we want -> to do doesn’t require capturing a value from the environment, we can use a -> function rather than a closure where we need something that implements an `Fn` -> trait. +> Note: Functions can implement all three of the `Fn` traits too. If what we +> want to do doesn’t require capturing a value from the environment, we can use +> a function rather than a closure where we need something that implements an +> `Fn` trait. The `value` field is of type `Option`. Before we execute the closure, `value` will be `None`. When code using a `Cacher` asks for the *result* of the diff --git a/src/doc/book/2018-edition/src/ch14-03-cargo-workspaces.md b/src/doc/book/2018-edition/src/ch14-03-cargo-workspaces.md index 72f83a93af..f598d0213b 100644 --- a/src/doc/book/2018-edition/src/ch14-03-cargo-workspaces.md +++ b/src/doc/book/2018-edition/src/ch14-03-cargo-workspaces.md @@ -44,7 +44,7 @@ Next, we’ll create the `adder` binary crate by running `cargo new` within the *add* directory: ```text -$ cargo new --bin adder +$ cargo new adder Created binary (application) `adder` project ``` @@ -92,7 +92,7 @@ members = [ Then generate a new library crate named `add-one`: ```text -$ cargo new add-one +$ cargo new add-one --lib Created library `add-one` project ``` diff --git a/src/doc/book/2018-edition/src/ch15-02-deref.md b/src/doc/book/2018-edition/src/ch15-02-deref.md index 4eb9a4a779..c9935916d8 100644 --- a/src/doc/book/2018-edition/src/ch15-02-deref.md +++ b/src/doc/book/2018-edition/src/ch15-02-deref.md @@ -14,6 +14,11 @@ smart pointers to work in a similar way as references. Then we’ll look at Rust’s *deref coercion* feature and how it lets us work with either references or smart pointers. +> There's one big difference between the `MyBox` type we're about to build +> and the real `Box`: our version will not store its data on the heap. We +> are focusing this example on `Deref`, and so where the data is actually stored +> is less important than the pointer-like behavior. + ### Following the Pointer to the Value with the Dereference Operator A regular reference is a type of pointer, and one way to think of a pointer is diff --git a/src/doc/book/2018-edition/src/ch17-02-trait-objects.md b/src/doc/book/2018-edition/src/ch17-02-trait-objects.md index fcccc11825..a4ac4e3108 100644 --- a/src/doc/book/2018-edition/src/ch17-02-trait-objects.md +++ b/src/doc/book/2018-edition/src/ch17-02-trait-objects.md @@ -43,12 +43,13 @@ To implement the behavior we want `gui` to have, we’ll define a trait named takes a *trait object*. A trait object points to an instance of a type that implements the trait we specify. We create a trait object by specifying some sort of pointer, such as a `&` reference or a `Box` smart pointer, and then -specifying the relevant trait. (We’ll talk about the reason trait objects must -use a pointer in Chapter 19 in the section “Dynamically Sized Types & Sized”.) -We can use trait objects in place of a generic or concrete type. Wherever we -use a trait object, Rust’s type system will ensure at compile time that any -value used in that context will implement the trait object’s trait. -Consequently, we don’t need to know all the possible types at compile time. +specifying the relevant trait, and add a `dyn` keyword. (We’ll talk about the +reason trait objects must use a pointer in Chapter 19 in the section +“Dynamically Sized Types & Sized”.) We can use trait objects in place of a +generic or concrete type. Wherever we use a trait object, Rust’s type system +will ensure at compile time that any value used in that context will +implement the trait object’s trait. Consequently, we don’t need to know all +the possible types at compile time. We’ve mentioned that in Rust, we refrain from calling structs and enums “objects” to distinguish them from other languages’ objects. In a struct or @@ -77,8 +78,8 @@ pub trait Draw { This syntax should look familiar from our discussions on how to define traits in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named `Screen` that holds a vector named `components`. This vector is of type -`Box`, which is a trait object; it’s a stand-in for any type inside a -`Box` that implements the `Draw` trait. +`Box`, which is a trait object; it’s a stand-in for any type inside +a `Box` that implements the `Draw` trait. Filename: src/lib.rs @@ -88,7 +89,7 @@ in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named # } # pub struct Screen { - pub components: Vec>, + pub components: Vec>, } ``` @@ -107,7 +108,7 @@ On the `Screen` struct, we’ll define a method named `run` that will call the # } # # pub struct Screen { -# pub components: Vec>, +# pub components: Vec>, # } # impl Screen { @@ -280,8 +281,8 @@ then it must be a duck! In the implementation of `run` on `Screen` in Listing 17-5, `run` doesn’t need to know what the concrete type of each component is. It doesn’t check whether a component is an instance of a `Button` or a `SelectBox`, it just calls the `draw` method on the component. By specifying -`Box` as the type of the values in the `components` vector, we’ve defined -`Screen` to need values that we can call the `draw` method on. +`Box` as the type of the values in the `components` vector, we’ve +defined `Screen` to need values that we can call the `draw` method on. The advantage of using trait objects and Rust’s type system to write code similar to code using duck typing is that we never have to check whether a @@ -397,7 +398,7 @@ implement the `Clone` trait instead of the `Draw` trait, like this: ```rust,ignore pub struct Screen { - pub components: Vec>, + pub components: Vec>, } ``` @@ -407,7 +408,7 @@ We would get this error: error[E0038]: the trait `std::clone::Clone` cannot be made into an object --> src/lib.rs:2:5 | -2 | pub components: Vec>, +2 | pub components: Vec>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` cannot be made into an object | diff --git a/src/doc/book/2018-edition/src/ch17-03-oo-design-patterns.md b/src/doc/book/2018-edition/src/ch17-03-oo-design-patterns.md index 0d2b60d5c4..80d61fc5a6 100644 --- a/src/doc/book/2018-edition/src/ch17-03-oo-design-patterns.md +++ b/src/doc/book/2018-edition/src/ch17-03-oo-design-patterns.md @@ -83,15 +83,15 @@ Let’s get started on the implementation of the library! We know we need a public `Post` struct that holds some content, so we’ll start with the definition of the struct and an associated public `new` function to create an instance of `Post`, as shown in Listing 17-12. We’ll also make a private -`State` trait. Then `Post` will hold a trait object of `Box` inside an -`Option` in a private field named `state`. You’ll see why the `Option` is -necessary in a bit. +`State` trait. Then `Post` will hold a trait object of `Box` +inside an `Option` in a private field named `state`. You’ll see why the +`Option` is necessary in a bit. Filename: src/lib.rs ```rust pub struct Post { - state: Option>, + state: Option>, content: String, } @@ -204,7 +204,7 @@ change its state from `Draft` to `PendingReview`. Listing 17-15 shows this code: ```rust # pub struct Post { -# state: Option>, +# state: Option>, # content: String, # } # @@ -218,13 +218,13 @@ impl Post { } trait State { - fn request_review(self: Box) -> Box; + fn request_review(self: Box) -> Box; } struct Draft {} impl State for Draft { - fn request_review(self: Box) -> Box { + fn request_review(self: Box) -> Box { Box::new(PendingReview {}) } } @@ -232,7 +232,7 @@ impl State for Draft { struct PendingReview {} impl State for PendingReview { - fn request_review(self: Box) -> Box { + fn request_review(self: Box) -> Box { self } } @@ -293,7 +293,7 @@ state is approved, as shown in Listing 17-16: ```rust # pub struct Post { -# state: Option>, +# state: Option>, # content: String, # } # @@ -307,19 +307,19 @@ impl Post { } trait State { - fn request_review(self: Box) -> Box; - fn approve(self: Box) -> Box; + fn request_review(self: Box) -> Box; + fn approve(self: Box) -> Box; } struct Draft {} impl State for Draft { -# fn request_review(self: Box) -> Box { +# fn request_review(self: Box) -> Box { # Box::new(PendingReview {}) # } # // --snip-- - fn approve(self: Box) -> Box { + fn approve(self: Box) -> Box { self } } @@ -327,12 +327,12 @@ impl State for Draft { struct PendingReview {} impl State for PendingReview { -# fn request_review(self: Box) -> Box { +# fn request_review(self: Box) -> Box { # self # } # // --snip-- - fn approve(self: Box) -> Box { + fn approve(self: Box) -> Box { Box::new(Published {}) } } @@ -340,11 +340,11 @@ impl State for PendingReview { struct Published {} impl State for Published { - fn request_review(self: Box) -> Box { + fn request_review(self: Box) -> Box { self } - fn approve(self: Box) -> Box { + fn approve(self: Box) -> Box { self } } @@ -374,7 +374,7 @@ otherwise, we want to return an empty string slice, as shown in Listing 17-17: # fn content<'a>(&self, post: &'a Post) -> &'a str; # } # pub struct Post { -# state: Option>, +# state: Option>, # content: String, # } # @@ -397,7 +397,7 @@ returned from using the `content` method on the `state` value. We call the `as_ref` method on the `Option` because we want a reference to the value inside the `Option` rather than ownership of the value. Because `state` -is an `Option>`, when we call `as_ref`, an `Option<&Box>` is +is an `Option>`, when we call `as_ref`, an `Option<&Box>` is returned. If we didn’t call `as_ref`, we would get an error because we can’t move `state` out of the borrowed `&self` of the function parameter. @@ -408,7 +408,7 @@ the “Cases When You Have More Information Than the Compiler” section of Chap 9 when we know that a `None` value is never possible, even though the compiler isn’t able to understand that. -At this point, when we call `content` on the `&Box`, deref coercion will +At this point, when we call `content` on the `&Box`, deref coercion will take effect on the `&` and the `Box` so the `content` method will ultimately be called on the type that implements the `State` trait. That means we need to add `content` to the `State` trait definition, and that is where we’ll put the diff --git a/src/doc/book/2018-edition/src/ch18-00-patterns.md b/src/doc/book/2018-edition/src/ch18-00-patterns.md index c54a55dc28..e1cc752642 100644 --- a/src/doc/book/2018-edition/src/ch18-00-patterns.md +++ b/src/doc/book/2018-edition/src/ch18-00-patterns.md @@ -17,12 +17,12 @@ to continue running a particular piece of code. To use a pattern, we compare it to some value. If the pattern matches the value, we use the value parts in our code. Recall the `match` expressions in -Chapter 6 that used patterns, such as the coin sorting machine example. If the +Chapter 6 that used patterns, such as the coin-sorting machine example. If the value fits the shape of the pattern, we can use the named pieces. If it doesn’t, the code associated with the pattern won’t run. This chapter is a reference on all things related to patterns. We’ll cover the -valid places to use patterns, the difference between *refutable* and -*irrefutable* patterns, and the different kinds of pattern syntax that you -might see. By the end of the chapter, you’ll know how to use patterns to -express many concepts in a clear way. +valid places to use patterns, the difference between refutable and irrefutable +patterns, and the different kinds of pattern syntax that you might see. By the +end of the chapter, you’ll know how to use patterns to express many concepts in +a clear way. diff --git a/src/doc/book/2018-edition/src/ch18-01-all-the-places-for-patterns.md b/src/doc/book/2018-edition/src/ch18-01-all-the-places-for-patterns.md index 6b41103118..7702350b4a 100644 --- a/src/doc/book/2018-edition/src/ch18-01-all-the-places-for-patterns.md +++ b/src/doc/book/2018-edition/src/ch18-01-all-the-places-for-patterns.md @@ -1,8 +1,8 @@ ## All the Places Patterns Can Be Used Patterns pop up in a number of places in Rust, and you’ve been using them a lot -without realizing it! This section provides you with a reference to all the -places where patterns are valid. +without realizing it! This section discusses all the places where patterns are +valid. ### `match` Arms @@ -40,20 +40,14 @@ the pattern in the `if let` doesn’t match. Listing 18-1 shows that it’s also possible to mix and match `if let`, `else if`, and `else if let` expressions. Doing so gives us more flexibility than a -`match` expression in which we can only express one value to compare with the +`match` expression in which we can express only one value to compare with the patterns. Also, the conditions in a series of `if let`, `else if`, `else if let` arms aren’t required to relate to each other. -The code in Listing 18-1 shows a series of checks for several different -conditions that decide what the background color should be. For this example, -we’ve created variables with hardcoded values that a real program might receive -from user input. - -If the user specifies a favorite color, that color is the background color. If -today is Tuesday, the background color will be green. If the user specifies -their age as a string and we can parse it as a number successfully, the color -is either purple or orange depending on the value of the number. If none of -these conditions apply, the background color will be blue: +The code in Listing 18-1 shows a series of checks for several conditions that +decide what the background color should be. For this example, we’ve created +variables with hardcoded values that a real program might receive from user +input. Filename: src/main.rs @@ -82,6 +76,12 @@ fn main() { Listing 18-1: Mixing `if let`, `else if`, `else if let`, and `else` +If the user specifies a favorite color, that color is the background color. If +today is Tuesday, the background color is green. If the user specifies +their age as a string and we can parse it as a number successfully, the color +is either purple or orange depending on the value of the number. If none of +these conditions apply, the background color is blue. + This conditional structure lets us support complex requirements. With the hardcoded values we have here, this example will print `Using purple as the background color`. @@ -104,7 +104,7 @@ not alert us to the possible logic bug. Similar in construction to `if let`, the `while let` conditional loop allows a `while` loop to run for as long as a pattern continues to match. The example in Listing 18-2 shows a `while let` loop that uses a vector as a stack and prints -out the values in the vector in the opposite order in which they were pushed: +the values in the vector in the opposite order in which they were pushed. ```rust let mut stack = Vec::new(); @@ -118,8 +118,8 @@ while let Some(top) = stack.pop() { } ``` -Listing 18-2: Using a `while let` loop to print out -values for as long as `stack.pop()` returns `Some` +Listing 18-2: Using a `while let` loop to print values +for as long as `stack.pop()` returns `Some` This example prints 3, 2, and then 1. The `pop` method takes the last element out of the vector and returns `Some(value)`. If the vector is empty, `pop` @@ -129,13 +129,13 @@ use `while let` to pop every element off our stack. ### `for` Loops -In Chapter 3 we mentioned that the `for` loop is the most common loop +In Chapter 3, we mentioned that the `for` loop is the most common loop construction in Rust code, but we haven’t yet discussed the pattern that `for` takes. In a `for` loop, the pattern is the value that directly follows the keyword `for`, so in `for x in y` the `x` is the pattern. Listing 18-3 demonstrates how to use a pattern in a `for` loop to destructure, -or break apart, a tuple as part of the `for` loop: +or break apart, a tuple as part of the `for` loop. ```rust let v = vec!['a', 'b', 'c']; @@ -189,7 +189,7 @@ the variable `x`.” Because the name `x` is the whole pattern, this pattern effectively means “bind everything to the variable `x`, whatever the value is.” To see the pattern matching aspect of `let` more clearly, consider Listing -18-4, which uses a pattern with `let` to destructure a tuple: +18-4, which uses a pattern with `let` to destructure a tuple. ```rust let (x, y, z) = (1, 2, 3); @@ -206,7 +206,7 @@ pattern as nesting three individual variable patterns inside it. If the number of elements in the pattern doesn’t match the number of elements in the tuple, the overall type won’t match and we’ll get a compiler error. For example, Listing 18-5 shows an attempt to destructure a tuple with three -elements into two variables, which won’t work: +elements into two variables, which won’t work. ```rust,ignore let (x, y) = (1, 2, 3); @@ -229,7 +229,7 @@ error[E0308]: mismatched types ``` If we wanted to ignore one or more of the values in the tuple, we could use `_` -or `..` as you’ll see in the “Ignoring Values in a Pattern” section. If the +or `..`, as you’ll see in the “Ignoring Values in a Pattern” section. If the problem is that we have too many variables in the pattern, the solution is to make the types match by removing variables so the number of variables equals the number of elements in the tuple. @@ -238,7 +238,7 @@ the number of elements in the tuple. Function parameters can also be patterns. The code in Listing 18-6, which declares a function named `foo` that takes one parameter named `x` of type -`i32`, should by now look familiar: +`i32`, should by now look familiar. ```rust fn foo(x: i32) { @@ -251,7 +251,7 @@ parameters The `x` part is a pattern! As we did with `let`, we could match a tuple in a function’s arguments to the pattern. Listing 18-7 splits the values in a tuple -as we pass it to a function: +as we pass it to a function. Filename: src/main.rs @@ -278,5 +278,5 @@ discussed in Chapter 13. At this point, you’ve seen several ways of using patterns, but patterns don’t work the same in every place we can use them. In some places, the patterns must -be *irrefutable*, meaning they must match any value provided. In other -circumstances, they can be refutable. Let’s discuss these two concepts next. +be irrefutable; in other circumstances, they can be refutable. We’ll discuss +these two concepts next. diff --git a/src/doc/book/2018-edition/src/ch18-02-refutability.md b/src/doc/book/2018-edition/src/ch18-02-refutability.md index d4acc842fe..9d85f27404 100644 --- a/src/doc/book/2018-edition/src/ch18-02-refutability.md +++ b/src/doc/book/2018-edition/src/ch18-02-refutability.md @@ -5,8 +5,8 @@ for any possible value passed are *irrefutable*. An example would be `x` in the statement `let x = 5;` because `x` matches anything and therefore cannot fail to match. Patterns that can fail to match for some possible value are *refutable*. An example would be `Some(x)` in the expression `if let Some(x) = -a_value`; if the value in `a_value` variable is `None` rather than `Some`, the -`Some(x)` pattern would not match. +a_value` because if the value in the `a_value` variable is `None` rather than +`Some`, the `Some(x)` pattern will not match. Function parameters, `let` statements, and `for` loops can only accept irrefutable patterns, because the program cannot do anything meaningful when @@ -24,7 +24,7 @@ using the pattern with, depending on the intended behavior of the code. Let’s look at an example of what happens when we try to use a refutable pattern where Rust requires an irrefutable pattern and vice versa. Listing 18-8 shows a `let` statement, but for the pattern we’ve specified `Some(x)`, a refutable -pattern. As you might expect, this code will error: +pattern. As you might expect, this code will not compile. ```rust,ignore let Some(x) = some_option_value; @@ -54,7 +54,7 @@ To fix the problem where we have a refutable pattern where an irrefutable pattern is needed, we can change the code that uses the pattern: instead of using `let`, we can use `if let`. Then if the pattern doesn’t match, the code will just skip the code in the curly brackets, giving it a way to continue -validly. Listing 18-9 shows how to fix the code in Listing 18-8: +validly. Listing 18-9 shows how to fix the code in Listing 18-8. ```rust # let some_option_value: Option = None; @@ -69,7 +69,7 @@ patterns instead of `let` We’ve given the code an out! This code is perfectly valid, although it means we cannot use an irrefutable pattern without receiving an error. If we give `if let` a pattern that will always match, such as `x`, as shown in Listing 18-10, -it will error: +it will not compile. ```rust,ignore if let x = 5 { diff --git a/src/doc/book/2018-edition/src/ch18-03-pattern-syntax.md b/src/doc/book/2018-edition/src/ch18-03-pattern-syntax.md index 82c4319df0..eda6b54b05 100644 --- a/src/doc/book/2018-edition/src/ch18-03-pattern-syntax.md +++ b/src/doc/book/2018-edition/src/ch18-03-pattern-syntax.md @@ -1,8 +1,8 @@ -## All the Pattern Syntax +## Pattern Syntax -Throughout the book, you’ve seen examples of many different kinds of patterns. -In this section, we gather all the syntax valid in patterns and discuss why you -might want to use each of them. +Throughout the book, you’ve seen examples of many kinds of patterns. In this +section, we gather all the syntax valid in patterns and discuss why you might +want to use each one. ### Matching Literals @@ -35,7 +35,7 @@ with all variables. In Listing 18-11, we declare a variable named `x` with the value `Some(5)` and a variable `y` with the value `10`. We then create a `match` expression on the value `x`. Look at the patterns in the match arms and `println!` at the end, and try to figure out what the code will print before -running this code or reading further: +running this code or reading further. Filename: src/main.rs @@ -152,7 +152,7 @@ to use different parts of these values. Let’s walk through each value. #### Destructuring Structs Listing 18-12 shows a `Point` struct with two fields, `x` and `y`, that we can -break apart using a pattern with a `let` statement: +break apart using a pattern with a `let` statement. Filename: src/main.rs @@ -186,7 +186,7 @@ shorthand for patterns that match struct fields: you only need to list the name of the struct field, and the variables created from the pattern will have the same names. Listing 18-13 shows code that behaves in the same way as the code in Listing 18-12, but the variables created in the `let` pattern are `x` and -`y` instead of `a` and `b`: +`y` instead of `a` and `b`. Filename: src/main.rs @@ -219,7 +219,7 @@ destructure the other fields. Listing 18-14 shows a `match` expression that separates `Point` values into three cases: points that lie directly on the `x` axis (which is true when `y = -0`), on the `y` axis (`x = 0`), or neither: +0`), on the `y` axis (`x = 0`), or neither. Filename: src/main.rs @@ -262,7 +262,7 @@ destructured `Option` in Listing 6-5 in Chapter 6. One detail we haven’t mentioned explicitly is that the pattern to destructure an enum should correspond to the way the data stored within the enum is defined. As an example, in Listing 18-15 we use the `Message` enum from Listing 6-2 and write -a `match` with patterns that will destructure each inner value: +a `match` with patterns that will destructure each inner value. Filename: src/main.rs @@ -323,6 +323,51 @@ pattern is similar to the pattern we specify to match tuples. The number of variables in the pattern must match the number of elements in the variant we’re matching. +#### Destructuring Nested Structs & Enums + +Up until now, all of our examples have been matching structures that were one +level deep. Matching can work on nested structures too! + +We can refactor the example above to support both RGB and HSV colors: + +```rust +enum Color { + Rgb(i32, i32, i32), + Hsv(i32, i32, i32) +} + +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(Color), +} + +fn main() { + let msg = Message::ChangeColor(Color::Hsv(0, 160, 255)); + + match msg { + Message::ChangeColor(Color::Rgb(r, g, b)) => { + println!( + "Change the color to red {}, green {}, and blue {}", + r, + g, + b + ) + }, + Message::ChangeColor(Color::Hsv(h, s, v)) => { + println!( + "Change the color to hue {}, saturation {}, and value {}", + h, + s, + v + ) + } + _ => () + } +} +``` + #### Destructuring References When the value we’re matching to our pattern contains a reference, we need to @@ -334,8 +379,8 @@ iterate over references, but we want to use the values in the closure rather than the references. The example in Listing 18-16 iterates over references to `Point` instances in a -vector, and destructures the reference and the struct so we can perform -calculations on the `x` and `y` values easily: +vector, destructuring the reference and the struct so we can perform +calculations on the `x` and `y` values easily. ```rust # struct Point { @@ -363,7 +408,7 @@ is the result of squaring the `x` value and the `y` value, adding those together, and then adding the result for each `Point` in the `points` vector to get one number. -If we had not included the `&` in `&Point { x, y }` we’d get a type mismatch +If we had not included the `&` in `&Point { x, y }`, we’d get a type mismatch error, because `iter` would then iterate over references to the items in the vector rather than the actual values. The error would look like this: @@ -385,7 +430,7 @@ we tried to match directly to a `Point` value, not a reference to a `Point`. We can mix, match, and nest destructuring patterns in even more complex ways. The following example shows a complicated destructure where we nest structs and -tuples inside a tuple, and destructure all the primitive values out: +tuples inside a tuple and destructure all the primitive values out: ```rust # struct Point { @@ -414,10 +459,10 @@ parts of a value. Let’s explore how and why to use each of these patterns. #### Ignoring an Entire Value with `_` -We’ve used the underscore `_` as a wildcard pattern that will match any value +We’ve used the underscore (`_`) as a wildcard pattern that will match any value but not bind to the value. Although the underscore `_` pattern is especially useful as the last arm in a `match` expression, we can use it in any pattern, -including function parameters, as shown in Listing 18-17: +including function parameters, as shown in Listing 18-17. Filename: src/main.rs @@ -438,7 +483,7 @@ and will print `This code only uses the y parameter: 4`. In most cases when you no longer need a particular function parameter, you would change the signature so it doesn’t include the unused parameter. Ignoring -a function parameter can be especially useful in some cases: for example, when +a function parameter can be especially useful in some cases, for example, when implementing a trait when you need a certain type signature but the function body in your implementation doesn’t need one of the parameters. The compiler will then not warn about unused function parameters, as it would if you used a @@ -446,8 +491,8 @@ name instead. #### Ignoring Parts of a Value with a Nested `_` -We can also use `_` inside another pattern to ignore just part of a value: for -example, when we only want to test for part of a value but have no use for the +We can also use `_` inside another pattern to ignore just part of a value, for +example, when we want to test for only part of a value but have no use for the other parts in the corresponding code we want to run. Listing 18-18 shows code responsible for managing a setting’s value. The business requirements are that the user should not be allowed to overwrite an existing customization of a @@ -487,7 +532,7 @@ In all other cases (if either `setting_value` or `new_setting_value` are We can also use underscores in multiple places within one pattern to ignore particular values. Listing 18-19 shows an example of ignoring the second and -fourth values in a tuple of five items: +fourth values in a tuple of five items. ```rust let numbers = (2, 4, 8, 16, 32); @@ -504,7 +549,7 @@ match numbers { This code will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be ignored. -#### Ignoring an Unused Variable by Starting Its Name with an Underscore +#### Ignoring an Unused Variable by Starting Its Name with `_` If you create a variable but don’t use it anywhere, Rust will usually issue a warning because that could be a bug. But sometimes it’s useful to create a @@ -532,7 +577,7 @@ warning about not using the variable preceded by the underscore. Note that there is a subtle difference between using only `_` and using a name that starts with an underscore. The syntax `_x` still binds the value to the variable, whereas `_` doesn’t bind at all. To show a case where this -distinction matters, Listing 18-21 will provide us with an error: +distinction matters, Listing 18-21 will provide us with an error. ```rust,ignore let s = Some(String::from("Hello!")); @@ -550,7 +595,7 @@ underscore still binds the value, which might take ownership of the value We’ll receive an error because the `s` value will still be moved into `_s`, which prevents us from using `s` again. However, using the underscore by itself doesn’t ever bind to the value. Listing 18-22 will compile without any errors -because `s` doesn’t get moved into `_`: +because `s` doesn’t get moved into `_`. ```rust let s = Some(String::from("Hello!")); @@ -570,12 +615,12 @@ This code works just fine because we never bind `s` to anything; it isn’t move #### Ignoring Remaining Parts of a Value with `..` With values that have many parts, we can use the `..` syntax to use only a few -parts and ignore the rest, and avoid having to list underscores for each +parts and ignore the rest, avoiding the need to list underscores for each ignored value. The `..` pattern ignores any parts of a value that we haven’t explicitly matched in the rest of the pattern. In Listing 18-23, we have a `Point` struct that holds a coordinate in three-dimensional space. In the `match` expression, we want to operate only on the `x` coordinate and ignore -the values in the `y` and `z` fields: +the values in the `y` and `z` fields. ```rust struct Point { @@ -594,13 +639,13 @@ match origin { Listing 18-23: Ignoring all fields of a `Point` except for `x` by using `..` -We list the `x` value, and then just include the `..` pattern. This is quicker +We list the `x` value and then just include the `..` pattern. This is quicker than having to list `y: _` and `z: _`, particularly when we’re working with structs that have lots of fields in situations where only one or two fields are relevant. The syntax `..` will expand to as many values as it needs to be. Listing 18-24 -shows how to use `..` with a tuple: +shows how to use `..` with a tuple. Filename: src/main.rs @@ -623,8 +668,9 @@ In this code, the first and last value are matched with `first` and `last`. The `..` will match and ignore everything in the middle. However, using `..` must be unambiguous. If it is unclear which values are -intended for matching and which should be ignored, Rust will error. Listing -18-25 shows an example of using `..` ambiguously, so it will not compile: +intended for matching and which should be ignored, Rust will give us an error. +Listing 18-25 shows an example of using `..` ambiguously, so it will not +compile. Filename: src/main.rs @@ -654,14 +700,14 @@ error: `..` can only be used once per tuple or tuple struct pattern ``` It’s impossible for Rust to determine how many values in the tuple to ignore -before matching a value with `second`, and then how many further values to +before matching a value with `second` and then how many further values to ignore thereafter. This code could mean that we want to ignore `2`, bind `second` to `4`, and then ignore `8`, `16`, and `32`; or that we want to ignore `2` and `4`, bind `second` to `8`, and then ignore `16` and `32`; and so forth. The variable name `second` doesn’t mean anything special to Rust, so we get a compiler error because using `..` in two places like this is ambiguous. -### `ref` and `ref mut` to Create References in Patterns +### Creating References in Patterns with `ref` and `ref mut` Let’s look at using `ref` to make references so ownership of the values isn’t moved to variables in the pattern. Usually, when you match against a pattern, @@ -671,7 +717,7 @@ the pattern. Listing 18-26 shows an example of a `match` that has a pattern with a variable and then usage of the entire value in the `println!` statement later, after the `match`. This code will fail to compile because ownership of part of the `robot_name` value is transferred to the `name` variable in the -pattern of the first `match` arm: +pattern of the first `match` arm. ```rust,ignore let robot_name = Some(String::from("Bors")); @@ -702,7 +748,7 @@ reference in the value. Because `&` already has that meaning in patterns, we can’t use `&` to create a reference in a pattern. Instead, to create a reference in a pattern, we use the `ref` keyword before -the new variable, as shown in Listing 18-27: +the new variable, as shown in Listing 18-27. ```rust let robot_name = Some(String::from("Bors")); @@ -726,7 +772,7 @@ To create a mutable reference so we’re able to mutate a value matched in a pattern, we use `ref mut` instead of `&mut`. The reason is, again, that in patterns, the latter is for matching existing mutable references, not creating new ones. Listing 18-28 shows an example of a pattern creating a mutable -reference: +reference. ```rust let mut robot_name = Some(String::from("Bors")); @@ -755,7 +801,7 @@ than a pattern alone allows. The condition can use variables created in the pattern. Listing 18-29 shows a `match` where the first arm has the pattern `Some(x)` and also has a match -guard of `if x < 5`: +guard of `if x < 5`. ```rust let num = Some(4); @@ -783,11 +829,11 @@ There is no way to express the `if x < 5` condition within a pattern, so the match guard gives us the ability to express this logic. In Listing 18-11, we mentioned that we could use match guards to solve our -pattern shadowing problem. Recall that a new variable was created inside the +pattern-shadowing problem. Recall that a new variable was created inside the pattern in the `match` expression instead of using the variable outside the `match`. That new variable meant we couldn’t test against the value of the outer variable. Listing 18-30 shows how we can use a match guard to fix this -problem: +problem. Filename: src/main.rs @@ -826,7 +872,7 @@ patterns; the match guard condition will apply to all the patterns. Listing 18-31 shows the precedence of combining a match guard with a pattern that uses `|`. The important part of this example is that the `if y` match guard applies to `4`, `5`, *and* `6`, even though it might look like `if y` only applies to -`6`: +`6`. ```rust let x = 4; @@ -861,19 +907,19 @@ rather than this: ``` After running the code, the precedence behavior is evident: if the match guard -was only applied to the final value in the list of values specified using the +were applied only to the final value in the list of values specified using the `|` operator, the arm would have matched and the program would have printed `yes`. ### `@` Bindings -The *at* operator `@` lets us create a variable that holds a value at the same -time we’re testing that value to see whether it matches a pattern. Listing +The *at* operator (`@`) lets us create a variable that holds a value at the +same time we’re testing that value to see whether it matches a pattern. Listing 18-32 shows an example where we want to test that a `Message::Hello` `id` field is within the range `3...7`. But we also want to bind the value to the variable `id_variable` so we can use it in the code associated with the arm. We could name this variable `id`, the same as the field, but for this example we’ll use -a different name: +a different name. ```rust enum Message { @@ -902,18 +948,18 @@ This example will print `Found an id in range: 5`. By specifying `id_variable @` before the range `3...7`, we’re capturing whatever value matched the range while also testing that the value matched the range pattern. -In the second arm where we only have a range specified in the pattern, the code +In the second arm, where we only have a range specified in the pattern, the code associated with the arm doesn’t have a variable that contains the actual value of the `id` field. The `id` field’s value could have been 10, 11, or 12, but the code that goes with that pattern doesn’t know which it is. The pattern code isn’t able to use the value from the `id` field, because we haven’t saved the `id` value in a variable. -In the last arm where we’ve specified a variable without a range, we do have +In the last arm, where we’ve specified a variable without a range, we do have the value available to use in the arm’s code in a variable named `id`. The reason is that we’ve used the struct field shorthand syntax. But we haven’t -applied any test to the value in the `id` field in this arm, like we did with -the first two arms: any value would match this pattern. +applied any test to the value in the `id` field in this arm, as we did with the +first two arms: any value would match this pattern. Using `@` lets us test a value and save it in a variable within one pattern. diff --git a/src/doc/book/2018-edition/src/ch19-00-advanced-features.md b/src/doc/book/2018-edition/src/ch19-00-advanced-features.md index 8465edf9fe..683e335266 100644 --- a/src/doc/book/2018-edition/src/ch19-00-advanced-features.md +++ b/src/doc/book/2018-edition/src/ch19-00-advanced-features.md @@ -10,13 +10,13 @@ make sure you have a grasp of all the features Rust has to offer. In this chapter, we’ll cover: -* Unsafe Rust: How to opt out of some of Rust’s guarantees and take +* Unsafe Rust: how to opt out of some of Rust’s guarantees and take responsibility for manually upholding those guarantees -* Advanced lifetimes: Syntax for complex lifetime situations -* Advanced traits: Associated types, default type parameters, fully qualified +* Advanced lifetimes: syntax for complex lifetime situations +* Advanced traits: associated types, default type parameters, fully qualified syntax, supertraits, and the newtype pattern in relation to traits -* Advanced types: More about the newtype pattern, type aliases, the *never* - type, and dynamically sized types -* Advanced functions and closures: Function pointers and returning closures +* Advanced types: more about the newtype pattern, type aliases, the never type, + and dynamically sized types +* Advanced functions and closures: function pointers and returning closures It’s a panoply of Rust features with something for everyone! Let’s dive in! diff --git a/src/doc/book/2018-edition/src/ch19-01-unsafe-rust.md b/src/doc/book/2018-edition/src/ch19-01-unsafe-rust.md index 5de9742663..42d5deda39 100644 --- a/src/doc/book/2018-edition/src/ch19-01-unsafe-rust.md +++ b/src/doc/book/2018-edition/src/ch19-01-unsafe-rust.md @@ -7,27 +7,27 @@ and works just like regular Rust, but gives us extra superpowers. Unsafe Rust exists because, by nature, static analysis is conservative. When the compiler tries to determine whether or not code upholds the guarantees, -it’s better for it to reject some valid programs rather than accepting some +it’s better for it to reject some valid programs rather than accept some invalid programs. Although the code might be okay, as far as Rust is able to -tell, it’s not! In these cases, we can use unsafe code to tell the compiler, -“trust me, I know what I’m doing.” The downside is that we use it at our own -risk: if we use unsafe code incorrectly, problems due to memory unsafety, such +tell, it’s not! In these cases, you can use unsafe code to tell the compiler, +“Trust me, I know what I’m doing.” The downside is that you use it at your own +risk: if you use unsafe code incorrectly, problems due to memory unsafety, such as null pointer dereferencing, can occur. Another reason Rust has an unsafe alter ego is that the underlying computer -hardware is inherently unsafe. If Rust didn’t let us do unsafe operations, we -couldn’t do certain tasks. Rust needs to allow us to do low-level systems +hardware is inherently unsafe. If Rust didn’t let you do unsafe operations, you +couldn’t do certain tasks. Rust needs to allow you to do low-level systems programming, such as directly interacting with the operating system or even -writing our own operating system. Working with low-level systems programming is -one of the goals of the language. Let’s explore what we can do with unsafe Rust -and how to do it. +writing your own operating system. Working with low-level systems programming +is one of the goals of the language. Let’s explore what we can do with unsafe +Rust and how to do it. ### Unsafe Superpowers -To switch to unsafe Rust, we use the `unsafe` keyword, and then start a new -block that holds the unsafe code. We can take four actions in unsafe Rust, -which we call *unsafe superpowers*, that we can’t in safe Rust. Those -superpowers include the ability to: +To switch to unsafe Rust, use the `unsafe` keyword and then start a new block +that holds the unsafe code. You can take four actions in unsafe Rust, called +*unsafe superpowers*, that you can’t in safe Rust. Those superpowers include +the ability to: * Dereference a raw pointer * Call an unsafe function or method @@ -36,17 +36,17 @@ superpowers include the ability to: It’s important to understand that `unsafe` doesn’t turn off the borrow checker or disable any other of Rust’s safety checks: if you use a reference in unsafe -code, it will still be checked. The `unsafe` keyword only gives us access to +code, it will still be checked. The `unsafe` keyword only gives you access to these four features that are then not checked by the compiler for memory -safety. We still get some degree of safety inside of an unsafe block. +safety. You’ll still get some degree of safety inside of an unsafe block. In addition, `unsafe` does not mean the code inside the block is necessarily dangerous or that it will definitely have memory safety problems: the intent is -that as the programmer, we’ll ensure the code inside an `unsafe` block will +that as the programmer, you’ll ensure the code inside an `unsafe` block will access memory in a valid way. People are fallible, and mistakes will happen, but by requiring these four -unsafe operations to be inside blocks annotated with `unsafe` we’ll know that +unsafe operations to be inside blocks annotated with `unsafe` you’ll know that any errors related to memory safety must be within an `unsafe` block. Keep `unsafe` blocks small; you’ll be thankful later when you investigate memory bugs. @@ -60,7 +60,7 @@ from leaking out into all the places that you or your users might want to use the functionality implemented with `unsafe` code, because using a safe abstraction is safe. -Let’s look at each of the four unsafe superpowers in turn: we’ll also look at +Let’s look at each of the four unsafe superpowers in turn. We’ll also look at some abstractions that provide a safe interface to unsafe code. ### Dereferencing a Raw Pointer @@ -70,10 +70,10 @@ compiler ensures references are always valid. Unsafe Rust has two new types called *raw pointers* that are similar to references. As with references, raw pointers can be immutable or mutable and are written as `*const T` and `*mut T`, respectively. The asterisk isn’t the dereference operator; it’s part of the -type name. In the context of raw pointers, “immutable” means that the pointer +type name. In the context of raw pointers, *immutable* means that the pointer can’t be directly assigned to after being dereferenced. -Different from references and smart pointers, keep in mind that raw pointers: +Different from references and smart pointers, raw pointers: * Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location @@ -81,12 +81,12 @@ Different from references and smart pointers, keep in mind that raw pointers: * Are allowed to be null * Don’t implement any automatic cleanup -By opting out of having Rust enforce these guarantees, we can make the -trade-off of giving up guaranteed safety to gain performance or the ability to +By opting out of having Rust enforce these guarantees, you can give up +guaranteed safety in exchange for greater performance or the ability to interface with another language or hardware where Rust’s guarantees don’t apply. Listing 19-1 shows how to create an immutable and a mutable raw pointer from -references: +references. ```rust let mut num = 5; @@ -112,7 +112,7 @@ Listing 19-2 shows how to create a raw pointer to an arbitrary location in memory. Trying to use arbitrary memory is undefined: there might be data at that address or there might not, the compiler might optimize the code so there is no memory access, or the program might error with a segmentation fault. -Usually, there is no good reason to write code like this, but it is possible: +Usually, there is no good reason to write code like this, but it is possible. ```rust let address = 0x012345usize; @@ -124,7 +124,7 @@ memory address Recall that we can create raw pointers in safe code, but we can’t *dereference* raw pointers and read the data being pointed to. In Listing 19-3, we use the -dereference operator `*` on a raw pointer that requires an `unsafe` block: +dereference operator `*` on a raw pointer that requires an `unsafe` block. ```rust let mut num = 5; @@ -144,16 +144,16 @@ unsafe { Creating a pointer does no harm; it’s only when we try to access the value that it points at that we might end up dealing with an invalid value. -Note also that in Listing 19-1 and 19-3 we created `*const i32` and `*mut i32` +Note also that in Listing 19-1 and 19-3, we created `*const i32` and `*mut i32` raw pointers that both pointed to the same memory location, where `num` is stored. If we instead tried to create an immutable and a mutable reference to `num`, the code would not have compiled because Rust’s ownership rules don’t allow a mutable reference at the same time as any immutable references. With raw pointers, we can create a mutable pointer and an immutable pointer to the -same location, and change data through the mutable pointer, potentially -creating a data race. Be careful! +same location and change data through the mutable pointer, potentially creating +a data race. Be careful! -With all of these dangers, why would we ever use raw pointers? One major use +With all of these dangers, why would you ever use raw pointers? One major use case is when interfacing with C code, as you’ll see in the next section, “Calling an Unsafe Function or Method.” Another case is when building up safe abstractions that the borrow checker doesn’t understand. We’ll introduce unsafe @@ -210,7 +210,7 @@ a common abstraction. As an example, let’s study a function from the standard library, `split_at_mut`, that requires some unsafe code and explore how we might implement it. This safe method is defined on mutable slices: it takes one slice and makes it two by splitting the slice at the index given as an -argument. Listing 19-4 shows how to use `split_at_mut`: +argument. Listing 19-4 shows how to use `split_at_mut`. ```rust let mut v = vec![1, 2, 3, 4, 5, 6]; @@ -245,17 +245,17 @@ fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { Listing 19-5: An attempted implementation of `split_at_mut` using only safe Rust -This function first gets the total length of the slice, then it asserts that -the index given as a parameter is within the slice by checking that it’s less -than or equal to the length. The assertion means that if we pass an index that -is greater than the index to split the slice at, the function will panic before -it attempts to use that index. +This function first gets the total length of the slice. Then it asserts that +the index given as a parameter is within the slice by checking whether it’s +less than or equal to the length. The assertion means that if we pass an index +that is greater than the index to split the slice at, the function will panic +before it attempts to use that index. Then we return two mutable slices in a tuple: one from the start of the original slice to the `mid` index and another from `mid` to the end of the slice. -When we try to compile the code in Listing 19-5, we’ll get an error: +When we try to compile the code in Listing 19-5, we’ll get an error. ```text error[E0499]: cannot borrow `*slice` as mutable more than once at a time @@ -276,7 +276,7 @@ slices aren’t overlapping, but Rust isn’t smart enough to know this. When we know code is okay, but Rust doesn’t, it’s time to reach for unsafe code. Listing 19-6 shows how to use an `unsafe` block, a raw pointer, and some calls -to unsafe functions to make the implementation of `split_at_mut` work: +to unsafe functions to make the implementation of `split_at_mut` work. ```rust use std::slice; @@ -297,20 +297,20 @@ fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { Listing 19-6: Using unsafe code in the implementation of the `split_at_mut` function -Recall from the “Slices” section in Chapter 4 that slices are a pointer to some -data and the length of the slice. We use the `len` method to get the length of -a slice and the `as_mut_ptr` method to access the raw pointer of a slice. In -this case, because we have a mutable slice to `i32` values, `as_mut_ptr` -returns a raw pointer with the type `*mut i32`, which we’ve stored in the -variable `ptr`. +Recall from “The Slice Type” section in Chapter 4 that slices are a pointer to +some data and the length of the slice. We use the `len` method to get the +length of a slice and the `as_mut_ptr` method to access the raw pointer of a +slice. In this case, because we have a mutable slice to `i32` values, +`as_mut_ptr` returns a raw pointer with the type `*mut i32`, which we’ve stored +in the variable `ptr`. We keep the assertion that the `mid` index is within the slice. Then we get to the unsafe code: the `slice::from_raw_parts_mut` function takes a raw pointer -and a length, and creates a slice. We use this function to create a slice that -starts from `ptr` and is `mid` items long. Then we call the `offset` method on -`ptr` with `mid` as an argument to get a raw pointer that starts at `mid`, and -we create a slice using that pointer and the remaining number of items after -`mid` as the length. +and a length, and it creates a slice. We use this function to create a slice +that starts from `ptr` and is `mid` items long. Then we call the `offset` +method on `ptr` with `mid` as an argument to get a raw pointer that starts at +`mid`, and we create a slice using that pointer and the remaining number of +items after `mid` as the length. The function `slice::from_raw_parts_mut` is unsafe because it takes a raw pointer and must trust that this pointer is valid. The `offset` method on raw @@ -330,7 +330,7 @@ data this function has access to. In contrast, the use of `slice::from_raw_parts_mut` in Listing 19-7 would likely crash when the slice is used. This code takes an arbitrary memory -location and creates a slice ten thousand items long: +location and creates a slice 10,000 items long. ```rust use std::slice; @@ -360,7 +360,7 @@ programming language to call those functions. Listing 19-8 demonstrates how to set up an integration with the `abs` function from the C standard library. Functions declared within `extern` blocks are -always unsafe to call from Rust code. The reason is that other languages don`t +always unsafe to call from Rust code. The reason is that other languages don’t enforce Rust’s rules and guarantees, and Rust can’t check them, so responsibility falls on the programmer to ensure safety. @@ -387,30 +387,30 @@ functions from another language we want to call. The `"C"` part defines which defines how to call the function at the assembly level. The `"C"` ABI is the most common and follows the C programming language’s ABI. -#### Calling Rust Functions from Other Languages - -We can also use `extern` to create an interface that allows other languages to -call Rust functions. Instead of an `extern` block, we add the `extern` keyword -and specify the ABI to use just before the `fn` keyword. We also need to add a -`#[no_mangle]` annotation to tell the Rust compiler not to mangle the name of -this function. *Mangling* is when a compiler changes the name we’ve given a -function to a different name that contains more information for other parts of -the compilation process to consume but is less human readable. Every -programming language compiler mangles names slightly differently, so for a Rust -function to be nameable by other languages, we must disable the Rust compiler’s -name mangling. - -In the following example, we make the `call_from_c` function accessible from C -code, after it’s compiled to a shared library and linked from C: - -```rust -#[no_mangle] -pub extern "C" fn call_from_c() { - println!("Just called a Rust function from C!"); -} -``` - -This usage of `extern` does not require `unsafe`. +> #### Calling Rust Functions from Other Languages +> +> We can also use `extern` to create an interface that allows other languages +> to call Rust functions. Instead of an `extern` block, we add the `extern` +> keyword and specify the ABI to use just before the `fn` keyword. We also need +> to add a `#[no_mangle]` annotation to tell the Rust compiler not to mangle +> the name of this function. *Mangling* is when a compiler changes the name +> we’ve given a function to a different name that contains more information for +> other parts of the compilation process to consume but is less human readable. +> Every programming language compiler mangles names slightly differently, so +> for a Rust function to be nameable by other languages, we must disable the +> Rust compiler’s name mangling. +> +> In the following example, we make the `call_from_c` function accessible from +> C code, after it’s compiled to a shared library and linked from C: +> +> ```rust +> #[no_mangle] +> pub extern "C" fn call_from_c() { +> println!("Just called a Rust function from C!"); +> } +> ``` +> +> This usage of `extern` does not require `unsafe`. ### Accessing or Modifying a Mutable Static Variable @@ -420,7 +420,7 @@ accessing the same mutable global variable, it can cause a data race. In Rust, global variables are called *static* variables. Listing 19-9 shows an example declaration and use of a static variable with a string slice as a -value: +value. Filename: src/main.rs @@ -451,7 +451,7 @@ are allowed to duplicate their data whenever they’re used. Another difference between constants and static variables is that static variables can be mutable. Accessing and modifying mutable static variables is *unsafe*. Listing 19-10 shows how to declare, access, and modify a mutable -static variable named `COUNTER`: +static variable named `COUNTER`. Filename: src/main.rs @@ -485,16 +485,16 @@ races. With mutable data that is globally accessible, it’s difficult to ensure there are no data races, which is why Rust considers mutable static variables to be unsafe. Where possible, it’s preferable to use the concurrency techniques and -thread-safe smart pointers we discussed in Chapter 16, so the compiler checks +thread-safe smart pointers we discussed in Chapter 16 so the compiler checks that data accessed from different threads is done safely. ### Implementing an Unsafe Trait -The final action that only works with `unsafe` is implementing an unsafe trait. +The final action that works only with `unsafe` is implementing an unsafe trait. A trait is unsafe when at least one of its methods has some invariant that the compiler can’t verify. We can declare that a trait is `unsafe` by adding the -`unsafe` keyword before `trait`; then implementation of the trait must be -marked as `unsafe` too, as shown in Listing 19-11: +`unsafe` keyword before `trait` and marking the implementation of the trait as +`unsafe` too, as shown in Listing 19-11. ```rust unsafe trait Foo { diff --git a/src/doc/book/2018-edition/src/ch19-02-advanced-lifetimes.md b/src/doc/book/2018-edition/src/ch19-02-advanced-lifetimes.md index 6774c42c72..eb2537c95c 100644 --- a/src/doc/book/2018-edition/src/ch19-02-advanced-lifetimes.md +++ b/src/doc/book/2018-edition/src/ch19-02-advanced-lifetimes.md @@ -6,12 +6,12 @@ lifetimes of different references relate. You saw how every reference has a lifetime, but most of the time, Rust will let you elide lifetimes. Now we’ll look at three advanced features of lifetimes that we haven’t covered yet: -* Lifetime subtyping: Ensures that one lifetime outlives another lifetime -* Lifetime bounds: Specifies a lifetime for a reference to a generic type -* Inference of trait object lifetimes: How the compiler infers trait object - lifetimes and when they need to be specified +* Lifetime subtyping: ensures that one lifetime outlives another lifetime +* Lifetime bounds: specifies a lifetime for a reference to a generic type +* Inference of trait object lifetimes: allows the compiler to infer trait + object lifetimes and when they need to be specified -### Lifetime Subtyping Ensures One Lifetime Outlives Another +### Ensuring One Lifetime Outlives Another with Lifetime Subtyping *Lifetime subtyping* specifies that one lifetime should outlive another lifetime. To explore lifetime subtyping, imagine we want to write a parser. @@ -19,7 +19,7 @@ We’ll use a structure called `Context` that holds a reference to the string we’re parsing. We’ll write a parser that will parse this string and return success or failure. The parser will need to borrow the `Context` to do the parsing. Listing 19-12 implements this parser code, except the code doesn’t -have the required lifetime annotations, so it won’t compile: +have the required lifetime annotations, so it won’t compile. Filename: src/lib.rs @@ -37,13 +37,14 @@ impl Parser { } ``` -Listing 19-12: Defining a parser without lifetime annotations +Listing 19-12: Defining a parser without lifetime +annotations Compiling the code results in errors because Rust expects lifetime parameters on the string slice in `Context` and the reference to a `Context` in `Parser`. For simplicity’s sake, the `parse` function returns `Result<(), &str>`. That -is, the function will do nothing on success, and on failure will return the +is, the function will do nothing on success and, on failure, will return the part of the string slice that didn’t parse correctly. A real implementation would provide more error information and would return a structured data type when parsing succeeds. We won’t be discussing those details because they aren’t @@ -60,8 +61,12 @@ lifetimes involved. To get this code to compile, we need to fill in the lifetime parameters for the string slice in `Context` and the reference to the `Context` in `Parser`. The -most straightforward way to do this is to use the same lifetime everywhere, as -shown in Listing 19-13: +most straightforward way to do this is to use the same lifetime name +everywhere, as shown in Listing 19-13. Recall from the “Lifetime Annotations in +Struct Definitions” section in Chapter 10 that each of `struct Context<'a>`, +`struct Parser<'a>`, and `impl<'a>` is declaring a new lifetime parameter. +While their names happen to all be the same, the three lifetime parameters +declared in this example aren’t related. Filename: src/lib.rs @@ -80,17 +85,17 @@ impl<'a> Parser<'a> { ``` Listing 19-13: Annotating all references in `Context` and -`Parser` with the same lifetime parameter +`Parser` with lifetime parameters This code compiles just fine. It tells Rust that a `Parser` holds a reference -to a `Context` with lifetime `'a`, and that `Context` holds a string slice that +to a `Context` with lifetime `'a` and that `Context` holds a string slice that also lives as long as the reference to the `Context` in `Parser`. Rust’s compiler error message stated that lifetime parameters were required for these references, and we’ve now added lifetime parameters. Next, in Listing 19-14, we’ll add a function that takes an instance of `Context`, uses a `Parser` to parse that context, and returns what `parse` -returns. This code doesn’t quite work: +returns. This code doesn’t quite work. Filename: src/lib.rs @@ -186,18 +191,18 @@ string slice that `Context` holds is the same as that of the lifetime of the reference to `Context` that `Parser` holds. The `parse_context` function can’t see that within the `parse` function, the -string slice returned will outlive `Context` and `Parser`, and that the +string slice returned will outlive `Context` and `Parser` and that the reference `parse_context` returns refers to the string slice, not to `Context` or `Parser`. By knowing what the implementation of `parse` does, we know that the only -reason the return value of `parse` is tied to the `Parser` is because it’s -referencing the `Parser`’s `Context`, which is referencing the string slice. -So, it’s really the lifetime of the string slice that `parse_context` needs to -care about. We need a way to tell Rust that the string slice in `Context` and -the reference to the `Context` in `Parser` have different lifetimes and that -the return value of `parse_context` is tied to the lifetime of the string slice -in `Context`. +reason the return value of `parse` is tied to the `Parser` instance is that +it’s referencing the `Parser` instance’s `Context`, which is referencing the +string slice. So, it’s really the lifetime of the string slice that +`parse_context` needs to care about. We need a way to tell Rust that the string +slice in `Context` and the reference to the `Context` in `Parser` have +different lifetimes and that the return value of `parse_context` is tied to the +lifetime of the string slice in `Context`. First, we’ll try giving `Parser` and `Context` different lifetime parameters, as shown in Listing 19-15. We’ll use `'s` and `'c` as lifetime parameter names @@ -266,8 +271,8 @@ referenced data in `Context` with lifetime `'s` needs to be constrained to guarantee that it lives longer than the reference with lifetime `'c`. If `'s` is not longer than `'c`, the reference to `Context` might not be valid. -Now we get to the point of this section: the Rust feature *lifetime* -*subtyping* specifies that one lifetime parameter lives at least as long as +Now we get to the point of this section: the Rust feature *lifetime +subtyping* specifies that one lifetime parameter lives at least as long as another one. In the angle brackets where we declare lifetime parameters, we can declare a lifetime `'a` as usual and declare a lifetime `'b` that lives at least as long as `'a` by declaring `'b` using the syntax `'b: 'a`. @@ -293,7 +298,7 @@ lifetime of the string slice is longer than the reference to the `Context`. That was a very long-winded example, but as we mentioned at the start of this chapter, Rust’s advanced features are very specific. You won’t often need the syntax we described in this example, but in such situations, you’ll know how to -refer to something you have a reference to. +refer to something and give it the necessary lifetime. ### Lifetime Bounds on References to Generic Types @@ -307,7 +312,7 @@ As an example, consider a type that is a wrapper over references. Recall the section in Chapter 15: its `borrow` and `borrow_mut` methods return the types `Ref` and `RefMut`, respectively. These types are wrappers over references that keep track of the borrowing rules at runtime. The definition of the `Ref` -struct is shown in Listing 19-16, without lifetime bounds for now: +struct is shown in Listing 19-16, without lifetime bounds for now. Filename: src/lib.rs @@ -316,7 +321,7 @@ struct Ref<'a, T>(&'a T); ``` Listing 19-16: Defining a struct to wrap a reference to a -generic type, without lifetime bounds to start +generic type, without lifetime bounds Without explicitly constraining the lifetime `'a` in relation to the generic parameter `T`, Rust will error because it doesn’t know how long the generic @@ -350,7 +355,7 @@ consider adding an explicit lifetime bound `T: 'a` so that the reference type ``` Listing 19-17 shows how to apply this advice by specifying the lifetime bound -when we declare the generic type `T`: +when we declare the generic type `T`. ```rust struct Ref<'a, T: 'a>(&'a T); @@ -366,7 +371,7 @@ long as `'a`. We could solve this problem in a different way, as shown in the definition of a `StaticRef` struct in Listing 19-18, by adding the `'static` lifetime bound on `T`. This means if `T` contains any references, they must have the `'static` -lifetime: +lifetime. ```rust struct StaticRef(&'static T); @@ -393,7 +398,7 @@ happens if the type implementing the trait in the trait object has a lifetime of its own. Consider Listing 19-19 where we have a trait `Red` and a struct `Ball`. The `Ball` struct holds a reference (and thus has a lifetime parameter) and also implements trait `Red`. We want to use an instance of `Ball` as the -trait object `Box`: +trait object `Box`. Filename: src/main.rs @@ -409,7 +414,7 @@ impl<'a> Red for Ball<'a> { } fn main() { let num = 5; - let obj = Box::new(Ball { diameter: &num }) as Box; + let obj = Box::new(Ball { diameter: &num }) as Box; } ``` @@ -425,14 +430,14 @@ rules for working with lifetimes and trait objects: is `'a`. * With a single `T: 'a` clause, the default lifetime of the trait object is `'a`. -* With multiple `T: 'a`-like clauses, there is no default lifetime; we must be +* With multiple clauses like `T: 'a`, there is no default lifetime; we must be explicit. When we must be explicit, we can add a lifetime bound on a trait object like -`Box` using the syntax `Box` or `Box`, depending -on whether the reference lives for the entire program or not. As with the other -bounds, the syntax adding a lifetime bound means that any implementor of the -`Red` trait that has references inside the type must have the same lifetime -specified in the trait object bounds as those references. +`Box` using the syntax `Box` or `Box`, depending on whether the reference lives for the entire program or not. +As with the other bounds, the syntax adding a lifetime bound means that any +implementor of the `Red` trait that has references inside the type must have +the same lifetime specified in the trait object bounds as those references. Next, let’s look at some other advanced features that manage traits. diff --git a/src/doc/book/2018-edition/src/ch19-03-advanced-traits.md b/src/doc/book/2018-edition/src/ch19-03-advanced-traits.md index d2e9bc5d5b..7a3a405ee0 100644 --- a/src/doc/book/2018-edition/src/ch19-03-advanced-traits.md +++ b/src/doc/book/2018-edition/src/ch19-03-advanced-traits.md @@ -4,7 +4,7 @@ We first covered traits in the “Traits: Defining Shared Behavior” section of Chapter 10, but as with lifetimes, we didn’t discuss the more advanced details. Now that you know more about Rust, we can get into the nitty-gritty. -### Associated Types Specify Placeholder Types in Trait Definitions +### Specifying Placeholder Types in Trait Definitions with Associated Types *Associated types* connect a type placeholder with a trait such that the trait method definitions can use these placeholder types in their signatures. The @@ -15,7 +15,7 @@ trait is implemented. We’ve described most of the advanced features in this chapter as being rarely needed. Associated types are somewhere in the middle: they’re used more rarely -than features explained in the rest of the book, but more commonly than many of +than features explained in the rest of the book but more commonly than many of the other features discussed in this chapter. One example of a trait with an associated type is the `Iterator` trait that the @@ -23,11 +23,12 @@ standard library provides. The associated type is named `Item` and stands in for the type of the values the type implementing the `Iterator` trait is iterating over. In “The `Iterator` Trait and the `next` Method” section of Chapter 13, we mentioned that the definition of the `Iterator` trait is as -shown in Listing 19-20: +shown in Listing 19-20. ```rust pub trait Iterator { type Item; + fn next(&mut self) -> Option; } ``` @@ -40,11 +41,9 @@ that it will return values of type `Option`. Implementors of the `Iterator` trait will specify the concrete type for `Item`, and the `next` method will return an `Option` containing a value of that concrete type. -#### Associated Types vs. Generics - -Associated types might seem like a similar concept to generics, in that they -allow us to define a function without specifying what types it can handle. So -why use associated types? +Associated types might seem like a similar concept to generics, in that the +latter allow us to define a function without specifying what types it can +handle. So why use associated types? Let’s examine the difference between the two concepts with an example from Chapter 13 that implements the `Iterator` trait on the `Counter` struct. In @@ -60,8 +59,8 @@ impl Iterator for Counter { // --snip-- ``` -This syntax seems comparable to generics. So why not just define the `Iterator` -trait with generics, as shown in Listing 19-21? +This syntax seems comparable to that of generics. So why not just define the +`Iterator` trait with generics, as shown in Listing 19-21? ```rust pub trait Iterator { @@ -73,13 +72,13 @@ pub trait Iterator { `Iterator` trait using generics The difference is that when using generics, as in Listing 19-21, we must -annotate the types in each implementation. The reason is that we can also -implement `Iterator for Counter` or any other type, which would give us -multiple implementations of `Iterator` for `Counter`. In other words, when a -trait has a generic parameter, it can be implemented for a type multiple times, -changing the concrete types of the generic type parameters each time. When we -use the `next` method on `Counter`, we would have to provide type annotations -to indicate which implementation of `Iterator` we want to use. +annotate the types in each implementation; because we can also implement +`Iterator for Counter` or any other type, we could have multiple +implementations of `Iterator` for `Counter`. In other words, when a trait has a +generic parameter, it can be implemented for a type multiple times, changing +the concrete types of the generic type parameters each time. When we use the +`next` method on `Counter`, we would have to provide type annotations to +indicate which implementation of `Iterator` we want to use. With associated types, we don’t need to annotate types because we can’t implement a trait on a type multiple times. In Listing 19-20 with the @@ -112,7 +111,7 @@ struct: ```rust use std::ops::Add; -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] struct Point { x: i32, y: i32, @@ -155,22 +154,22 @@ trait Add { ``` This code should look generally familiar: a trait with one method and an -associated type. The new part is `RHS=Self` in the angle brackets: this syntax -is called *default type parameters*. The `RHS` generic type parameter (short -for “right hand side”) defines the type of the `rhs` parameter in the `add` -method. If we don’t specify a concrete type for `RHS` when we implement the -`Add` trait, the type of `RHS` will default to `Self`, which will be the type -we’re implementing `Add` on. +associated type. The new part is `RHS=Self`: this syntax is called *default +type parameters*. The `RHS` generic type parameter (short for “right hand +side”) defines the type of the `rhs` parameter in the `add` method. If we don’t +specify a concrete type for `RHS` when we implement the `Add` trait, the type +of `RHS` will default to `Self`, which will be the type we’re implementing +`Add` on. When we implemented `Add` for `Point`, we used the default for `RHS` because we wanted to add two `Point` instances. Let’s look at an example of implementing the `Add` trait where we want to customize the `RHS` type rather than using the default. -We have two structs holding values in different units, `Millimeters` and -`Meters`. We want to add values in millimeters to values in meters and have the +We have two structs, `Millimeters` and `Meters`, holding values in different +units. We want to add values in millimeters to values in meters and have the implementation of `Add` do the conversion correctly. We can implement `Add` for -`Millimeters` with `Meters` as the `RHS`, as shown in Listing 19-23: +`Millimeters` with `Meters` as the `RHS`, as shown in Listing 19-23. Filename: src/lib.rs @@ -195,35 +194,35 @@ impl Add for Millimeters { To add `Millimeters` and `Meters`, we specify `impl Add` to set the value of the `RHS` type parameter instead of using the default of `Self`. -We use default type parameters in two main ways: +You’ll use default type parameters in two main ways: * To extend a type without breaking existing code * To allow customization in specific cases most users won’t need The standard library’s `Add` trait is an example of the second purpose: -usually, you’ll add two like types, but the `Add` trait provides the ability -for customizing beyond that. Using a default type parameter in the `Add` trait +usually, you’ll add two like types, but the `Add` trait provides the ability to +customize beyond that. Using a default type parameter in the `Add` trait definition means you don’t have to specify the extra parameter most of the time. In other words, a bit of implementation boilerplate isn’t needed, making it easier to use the trait. -The first purpose is similar to the second but in reverse: if we want to add a -type parameter to an existing trait, we can give it a default to let us extend -the functionality of the trait without breaking the existing implementation -code. +The first purpose is similar to the second but in reverse: if you want to add a +type parameter to an existing trait, you can give it a default to allow +extension of the functionality of the trait without breaking the existing +implementation code. ### Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name Nothing in Rust prevents a trait from having a method with the same name as -another trait’s method, nor does Rust prevent us from implementing both traits +another trait’s method, nor does Rust prevent you from implementing both traits on one type. It’s also possible to implement a method directly on the type with the same name as methods from traits. -When calling methods with the same name, we need to tell Rust which one we want -to use. Consider the code in Listing 19-24 where we’ve defined two traits, +When calling methods with the same name, you’ll need to tell Rust which one you +want to use. Consider the code in Listing 19-24 where we’ve defined two traits, `Pilot` and `Wizard`, that both have a method called `fly`. We then implement both traits on a type `Human` that already has a method named `fly` implemented -on it. Each `fly` method does something different: +on it. Each `fly` method does something different. Filename: src/main.rs @@ -257,12 +256,12 @@ impl Human { } ``` -Listing 19-24: Two traits defined to have a `fly` method -and implementations of those traits on the `Human` type in addition to a `fly` -method on `Human` directly +Listing 19-24: Two traits are defined to have a `fly` +method and are implemented on the `Human` type, and a `fly` method is +implemented on `Human` directly When we call `fly` on an instance of `Human`, the compiler defaults to calling -the method that is directly implemented on the type, as shown in Listing 19-25: +the method that is directly implemented on the type, as shown in Listing 19-25. Filename: src/main.rs @@ -304,12 +303,12 @@ fn main() { Listing 19-25: Calling `fly` on an instance of `Human` -Running this code will print `*waving arms furiously*`, which shows that Rust +Running this code will print `*waving arms furiously*`, showing that Rust called the `fly` method implemented on `Human` directly. To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait, we need to use more explicit syntax to specify which `fly` method we mean. -Listing 19-26 demonstrates this syntax: +Listing 19-26 demonstrates this syntax. Filename: src/main.rs @@ -355,8 +354,9 @@ want to call Specifying the trait name before the method name clarifies to Rust which implementation of `fly` we want to call. We could also write -`Human::fly(&person)`, which is equivalent to `person.fly()` that we used in -Listing 19-26 but is a bit longer to write if we don’t need to disambiguate. +`Human::fly(&person)`, which is equivalent to the `person.fly()` that we used +in Listing 19-26, but this is a bit longer to write if we don’t need to +disambiguate. Running this code prints the following: @@ -367,15 +367,15 @@ Up! ``` Because the `fly` method takes a `self` parameter, if we had two *types* that -both implement one *trait*, Rust can figure out which implementation of a trait -to use based on the type of `self`. +both implement one *trait*, Rust could figure out which implementation of a +trait to use based on the type of `self`. However, associated functions that are part of traits don’t have a `self` parameter. When two types in the same scope implement that trait, Rust can’t -figure out which type we mean unless we use *fully qualified syntax*. For +figure out which type you mean unless you use *fully qualified syntax*. For example, the `Animal` trait in Listing 19-27 has the associated function `baby_name`, the implementation of `Animal` for the struct `Dog`, and the -associated function `baby_name` defined on `Dog` directly: +associated function `baby_name` defined on `Dog` directly. Filename: src/main.rs @@ -404,8 +404,8 @@ fn main() { ``` Listing 19-27: A trait with an associated function and a -type that has an associated function with the same name that also implements -the trait +type with an associated function of the same name that also implements the +trait This code is for an animal shelter that wants to name all puppies Spot, which is implemented in the `baby_name` associated function that is defined on `Dog`. @@ -425,7 +425,7 @@ This output isn’t what we wanted. We want to call the `baby_name` function tha is part of the `Animal` trait that we implemented on `Dog` so the code prints `A baby dog is called a puppy`. The technique of specifying the trait name that we used in Listing 19-26 doesn’t help here; if we change `main` to the code in -Listing 19-28, we’ll get a compilation error: +Listing 19-28, we’ll get a compilation error. Filename: src/main.rs @@ -454,9 +454,8 @@ error[E0283]: type annotations required: cannot resolve `_: Animal` ``` To disambiguate and tell Rust that we want to use the implementation of -`Animal` for `Dog`, we need to use *fully qualified syntax*, which is the most -specific we can be when calling a function. Listing 19-29 demonstrates how to -use fully qualified syntax: +`Animal` for `Dog`, we need to use fully qualified syntax. Listing 19-29 +demonstrates how to use fully qualified syntax. Filename: src/main.rs @@ -504,18 +503,18 @@ In general, fully qualified syntax is defined as follows: ``` For associated functions, there would not be a `receiver`: there would only be -the list of other arguments. We could use fully qualified syntax everywhere -that we call functions or methods. However, we’re allowed to omit any part of -this syntax that Rust can figure out from other information in the program. We +the list of other arguments. You could use fully qualified syntax everywhere +that you call functions or methods. However, you’re allowed to omit any part of +this syntax that Rust can figure out from other information in the program. You only need to use this more verbose syntax in cases where there are multiple implementations that use the same name and Rust needs help to identify which -implementation we want to call. +implementation you want to call. ### Using Supertraits to Require One Trait’s Functionality Within Another Trait -Sometimes, we might need one trait to use another trait’s functionality. In -this case, we need to rely on the dependent trait also being implemented. The -trait we’re relying on is a *supertrait* of the trait we’re implementing. +Sometimes, you might need one trait to use another trait’s functionality. In +this case, you need to rely on the dependent trait’s also being implemented. +The trait you rely on is a *supertrait* of the trait you’re implementing. For example, let’s say we want to make an `OutlinePrint` trait with an `outline_print` method that will print a value framed in asterisks. That is, @@ -533,10 +532,10 @@ call `outline_print` on a `Point` instance that has `1` for `x` and `3` for In the implementation of `outline_print`, we want to use the `Display` trait’s functionality. Therefore, we need to specify that the `OutlinePrint` trait will -only work for types that also implement `Display` and provide the functionality +work only for types that also implement `Display` and provide the functionality that `OutlinePrint` needs. We can do that in the trait definition by specifying `OutlinePrint: Display`. This technique is similar to adding a trait bound to -the trait. Listing 19-30 shows an implementation of the `OutlinePrint` trait: +the trait. Listing 19-30 shows an implementation of the `OutlinePrint` trait. Filename: src/main.rs @@ -561,9 +560,10 @@ requires the functionality from `Display` Because we’ve specified that `OutlinePrint` requires the `Display` trait, we can use the `to_string` function that is automatically implemented for any type -that implements `Display`. If we tried to use `to_string` without adding`: -Display` after the trait name, we’d get an error saying that no method named -`to_string` was found for the type `&Self` in the current scope. +that implements `Display`. If we tried to use `to_string` without adding a +colon and specifying the `Display` trait after the trait name, we’d get an +error saying that no method named `to_string` was found for the type `&Self` in +the current scope. Let’s see what happens when we try to implement `OutlinePrint` on a type that doesn’t implement `Display`, such as the `Point` struct: @@ -588,7 +588,7 @@ error[E0277]: the trait bound `Point: std::fmt::Display` is not satisfied | 20 | impl OutlinePrint for Point {} | ^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter; - try using `:?` instead if you are using a format string +try using `:?` instead if you are using a format string | = help: the trait `std::fmt::Display` is not implemented for `Point` ``` @@ -617,25 +617,25 @@ Then implementing the `OutlinePrint` trait on `Point` will compile successfully, and we can call `outline_print` on a `Point` instance to display it within an outline of asterisks. -### The Newtype Pattern to Implement External Traits on External Types +### Using the Newtype Pattern to Implement External Traits on External Types In Chapter 10 in the “Implementing a Trait on a Type” section, we mentioned the orphan rule that states we’re allowed to implement a trait on a type as long as either the trait or the type are local to our crate. It’s possible to get around this restriction using the *newtype pattern*, which involves creating a -new type in a tuple struct. (We covered tuple structs in the “Tuple Structs -without Named Fields to Create Different Types” section of Chapter 5.) The -tuple struct will have one field and be a thin wrapper around the type we want -to implement a trait for. Then the wrapper type is local to our crate, and we -can implement the trait on the wrapper. *Newtype* is a term that originates +new type in a tuple struct. (We covered tuple structs in the “Using Tuple +Structs without Named Fields to Create Different Types” section of Chapter 5.) +The tuple struct will have one field and be a thin wrapper around the type we +want to implement a trait for. Then the wrapper type is local to our crate, and +we can implement the trait on the wrapper. *Newtype* is a term that originates from the Haskell programming language. There is no runtime performance penalty for using this pattern, and the wrapper type is elided at compile time. -As an example, let’s say we want to implement `Display` on `Vec`, which the +As an example, let’s say we want to implement `Display` on `Vec`, which the orphan rule prevents us from doing directly because the `Display` trait and the -`Vec` type are defined outside our crate. We can make a `Wrapper` struct that -holds an instance of `Vec`; then we can implement `Display` on `Wrapper` and -use the `Vec` value, as shown in Listing 19-31: +`Vec` type are defined outside our crate. We can make a `Wrapper` struct +that holds an instance of `Vec`; then we can implement `Display` on +`Wrapper` and use the `Vec` value, as shown in Listing 19-31. Filename: src/main.rs @@ -659,21 +659,21 @@ fn main() { Listing 19-31: Creating a `Wrapper` type around `Vec` to implement `Display` -The implementation of `Display` uses `self.0` to access the inner `Vec`, -because `Wrapper` is a tuple struct and `Vec` is the item at index 0 in the +The implementation of `Display` uses `self.0` to access the inner `Vec`, +because `Wrapper` is a tuple struct and `Vec` is the item at index 0 in the tuple. Then we can use the functionality of the `Display` type on `Wrapper`. The downside of using this technique is that `Wrapper` is a new type, so it doesn’t have the methods of the value it’s holding. We would have to implement -all the methods of `Vec` directly on `Wrapper` so it can delegate to `self.0`, -allowing us to treat `Wrapper` exactly like a `Vec`. If we wanted the new type -to have every method the inner type has, implementing the `Deref` trait -(discussed in Chapter 15 in the “Treating Smart Pointers like Regular -References with the `Deref` Trait” section) on the `Wrapper` to return the -inner type would be a solution. If we don’t want the `Wrapper` type to have all -the methods of the inner type, in order to restrict the `Wrapper` type’s -behavior for example, we would have to implement just the methods we do want -manually. +all the methods of `Vec` directly on `Wrapper` such that the methods +delegate to `self.0`, which would allow us to treat `Wrapper` exactly like a +`Vec`. If we wanted the new type to have every method the inner type has, +implementing the `Deref` trait (discussed in Chapter 15 in the “Treating Smart +Pointers like Regular References with the `Deref` Trait” section) on the +`Wrapper` to return the inner type would be a solution. If we don’t want the +`Wrapper` type to have all the methods of the inner type—for example, to +restrict the `Wrapper` type’s behavior—we would have to implement just the +methods we do want manually. Now you know how the newtype pattern is used in relation to traits; it’s also a useful pattern even when traits are not involved. Let’s switch focus and look diff --git a/src/doc/book/2018-edition/src/ch19-04-advanced-types.md b/src/doc/book/2018-edition/src/ch19-04-advanced-types.md index 16672f9c55..6ac5003a80 100644 --- a/src/doc/book/2018-edition/src/ch19-04-advanced-types.md +++ b/src/doc/book/2018-edition/src/ch19-04-advanced-types.md @@ -6,19 +6,18 @@ examine why newtypes are useful as types. Then we’ll move on to type aliases, feature similar to newtypes but with slightly different semantics. We’ll also discuss the `!` type and dynamically sized types. +> Note: The next section assumes you’ve read the earlier section “The Newtype +> Pattern to Implement External Traits on External Types.” + ### Using the Newtype Pattern for Type Safety and Abstraction -> Note: This section assumes you’ve read the earlier section “The Newtype -> Pattern to Implement External Traits on External Types”. - -The newtype pattern is useful for other tasks beyond what we’ve discussed so -far, including statically enforcing that values are never confused and as an -indication of the units of a value. You saw an example of using newtypes to -indicate units in Listing 19-23: recall that the `Millimeters` and `Meters` -structs wrapped `u32` values in a newtype. If we wrote a function with a -parameter of type `Millimeters`, we couldn’t compile a program that -accidentally tried to call that function with a value of type `Meters` or a -plain `u32`. +The newtype pattern is useful for tasks beyond those we’ve discussed so far, +including statically enforcing that values are never confused and indicating +the units of a value. You saw an example of using newtypes to indicate units in +Listing 19-23: recall that the `Millimeters` and `Meters` structs wrapped `u32` +values in a newtype. If we wrote a function with a parameter of type +`Millimeters`, we couldn’t compile a program that accidentally tried to call +that function with a value of type `Meters` or a plain `u32`. Another use of the newtype pattern is in abstracting away some implementation details of a type: the new type can expose a public API that is different from @@ -34,7 +33,7 @@ internally. The newtype pattern is a lightweight way to achieve encapsulation to hide implementation details, which we discussed in the “Encapsulation that Hides Implementation Details” section of Chapter 17. -### Type Aliases Create Type Synonyms +### Creating Type Synonyms with Type Aliases Along with the newtype pattern, Rust provides the ability to declare a *type alias* to give an existing type another name. For this we use the `type` @@ -67,21 +66,21 @@ The main use case for type synonyms is to reduce repetition. For example, we might have a lengthy type like this: ```rust,ignore -Box +Box ``` Writing this lengthy type in function signatures and as type annotations all over the code can be tiresome and error prone. Imagine having a project full of -code like that in Listing 19-32: +code like that in Listing 19-32. ```rust -let f: Box = Box::new(|| println!("hi")); +let f: Box = Box::new(|| println!("hi")); -fn takes_long_type(f: Box) { +fn takes_long_type(f: Box) { // --snip-- } -fn returns_long_type() -> Box { +fn returns_long_type() -> Box { // --snip-- # Box::new(|| ()) } @@ -91,10 +90,10 @@ fn returns_long_type() -> Box { A type alias makes this code more manageable by reducing the repetition. In Listing 19-33, we’ve introduced an alias named `Thunk` for the verbose type and -can replace all uses of the type with the shorter alias `Thunk`: +can replace all uses of the type with the shorter alias `Thunk`. ```rust -type Thunk = Box; +type Thunk = Box; let f: Thunk = Box::new(|| println!("hi")); @@ -145,7 +144,7 @@ type Result = Result; ``` Because this declaration is in the `std::io` module, we can use the fully -qualified alias `std::io::Result`; that is, a `Result` with the `E` +qualified alias `std::io::Result`—that is, a `Result` with the `E` filled in as `std::io::Error`. The `Write` trait function signatures end up looking like this: @@ -162,9 +161,9 @@ pub trait Write { The type alias helps in two ways: it makes code easier to write *and* it gives us a consistent interface across all of `std::io`. Because it’s an alias, it’s just another `Result`, which means we can use any methods that work on -`Result` with it, as well as special syntax like `?`. +`Result` with it, as well as special syntax like the `?` operator. -### The `!` Never Type that Never Returns +### The Never Type that Never Returns Rust has a special type named `!` that’s known in type theory lingo as the *empty type* because it has no values. We prefer to call it the *never type* @@ -181,9 +180,8 @@ This code is read as “the function `bar` returns never.” Functions that retu never are called *diverging functions*. We can’t create values of the type `!` so `bar` can never possibly return. -But what use is a type you can never create values for? Recall the code in -Chapter 2 that we added in the “Handling Invalid Input” section; we’ve -reproduced it here in Listing 19-34: +But what use is a type you can never create values for? Recall the code from +Listing 2-5; we’ve reproduced part of it here in Listing 19-34. ```rust # let guess = "3"; @@ -211,7 +209,7 @@ let guess = match guess.trim().parse() { ``` The type of `guess` in this code would have to be an integer *and* a string, -and Rust requires that `guess` can only have one type. So what does `continue` +and Rust requires that `guess` have only one type. So what does `continue` return? How were we allowed to return a `u32` from one arm and have another arm that ends with `continue` in Listing 19-34? @@ -242,10 +240,10 @@ impl Option { ``` In this code, the same thing happens as in the `match` in Listing 19-34: Rust -sees that `val` has the type `T` and `panic!` has the type `!` so the result of -the overall `match` expression is `T`. This code works because `panic!` doesn’t -produce a value; it ends the program. In the `None` case, we won’t be returning -a value from `unwrap`, so this code is valid. +sees that `val` has the type `T` and `panic!` has the type `!`, so the result +of the overall `match` expression is `T`. This code works because `panic!` +doesn’t produce a value; it ends the program. In the `None` case, we won’t be +returning a value from `unwrap`, so this code is valid. One final expression that has the type `!` is a `loop`: @@ -261,13 +259,13 @@ Here, the loop never ends, so `!` is the value of the expression. However, this wouldn’t be true if we included a `break`, because the loop would terminate when it got to the `break`. -### Dynamically Sized Types and `Sized` +### Dynamically Sized Types and the `Sized` Trait Due to Rust’s need to know certain details, such as how much space to allocate for a value of a particular type, there is a corner of its type system that can be confusing: the concept of *dynamically sized types*. Sometimes referred to as *DSTs* or *unsized types*, these types let us write code using values whose -size we can only know at runtime. +size we can know only at runtime. Let’s dig into the details of a dynamically sized type called `str`, which we’ve been using throughout the book. That’s right, not `&str`, but `str` on @@ -289,26 +287,26 @@ holding a dynamically sized type. So what do we do? In this case, you already know the answer: we make the types of `s1` and `s2` a `&str` rather than a `str`. Recall that in the “String -Slices” section of Chapter 4 we said the slice data structure stores the +Slices” section of Chapter 4, we said the slice data structure stores the starting position and the length of the slice. So although a `&T` is a single value that stores the memory address of where the `T` is located, a `&str` is *two* values: the address of the `str` and its length. As such, we can know the size of a `&str` value at compile time: it’s -two times the size of a `usize` in length. That is, we always know the size of -a `&str`, no matter how long the string it refers to is. In general, this is -the way in which dynamically sized types are used in Rust: they have an extra -bit of metadata that stores the size of the dynamic information. The golden -rule of dynamically sized types is that we must always put values of -dynamically sized types behind a pointer of some kind. +twice the length of a `usize`. That is, we always know the size of a `&str`, no +matter how long the string it refers to is. In general, this is the way in +which dynamically sized types are used in Rust: they have an extra bit of +metadata that stores the size of the dynamic information. The golden rule of +dynamically sized types is that we must always put values of dynamically sized +types behind a pointer of some kind. We can combine `str` with all kinds of pointers: for example, `Box` or `Rc`. In fact, you’ve seen this before but with a different dynamically sized type: traits. Every trait is a dynamically sized type we can refer to by using the name of the trait. In Chapter 17 in the “Using Trait Objects that Allow for Values of Different Types” section, we mentioned that to use traits -as trait objects, we must put them behind a pointer, such as `&Trait` or -`Box` (`Rc` would work too). +as trait objects, we must put them behind a pointer, such as `&dyn Trait` or +`Box` (`Rc` would work too). To work with DSTs, Rust has a particular trait called the `Sized` trait to determine whether or not a type’s size is known at compile time. This trait is @@ -330,7 +328,7 @@ fn generic(t: T) { } ``` -By default, generic functions will only work on types that have a known size at +By default, generic functions will work only on types that have a known size at compile time. However, you can use the following special syntax to relax this restriction: diff --git a/src/doc/book/2018-edition/src/ch19-05-advanced-functions-and-closures.md b/src/doc/book/2018-edition/src/ch19-05-advanced-functions-and-closures.md index 6d81575d44..0da4011609 100644 --- a/src/doc/book/2018-edition/src/ch19-05-advanced-functions-and-closures.md +++ b/src/doc/book/2018-edition/src/ch19-05-advanced-functions-and-closures.md @@ -6,13 +6,13 @@ closures, which include function pointers and returning closures. ### Function Pointers We’ve talked about how to pass closures to functions; you can also pass regular -functions to functions! This technique is useful when we want to pass a -function we’ve already defined rather than defining a new closure. We do this -using function pointers to allow us to use functions as arguments to other +functions to functions! This technique is useful when you want to pass a +function you’ve already defined rather than defining a new closure. Doing this +with function pointers will allow you to use functions as arguments to other functions. Functions coerce to the type `fn` (with a lowercase f), not to be -confused with the `Fn` closure trait. The `fn` type is called a function -pointer. The syntax for specifying that a parameter is a function pointer is -similar to that of closures, as shown in Listing 19-35: +confused with the `Fn` closure trait. The `fn` type is called a *function +pointer*. The syntax for specifying that a parameter is a function pointer is +similar to that of closures, as shown in Listing 19-35. Filename: src/main.rs @@ -45,7 +45,7 @@ parameter type directly rather than declaring a generic type parameter with one of the `Fn` traits as a trait bound. Function pointers implement all three of the closure traits (`Fn`, `FnMut`, and -`FnOnce`), so we can always pass a function pointer as an argument for a +`FnOnce`), so you can always pass a function pointer as an argument for a function that expects a closure. It’s best to write functions using a generic type and one of the closure traits so your functions can accept either functions or closures. @@ -54,7 +54,7 @@ An example of where you would want to only accept `fn` and not closures is when interfacing with external code that doesn’t have closures: C functions can accept functions as arguments, but C doesn’t have closures. -As an example of where we can use either a closure defined inline or a named +As an example of where you could use either a closure defined inline or a named function, let’s look at a use of `map`. To use the `map` function to turn a vector of numbers into a vector of strings, we could use a closure, like this: @@ -88,12 +88,12 @@ up compiling to the same code, so use whichever style is clearer to you. ### Returning Closures -Closures are represented by traits, which means we can’t return closures -directly. In most cases where we might want to return a trait, we can instead +Closures are represented by traits, which means you can’t return closures +directly. In most cases where you might want to return a trait, you can instead use the concrete type that implements the trait as the return value of the -function. But we can’t do that with closures because they don’t have a concrete -type that is returnable; we’re not allowed to use the function pointer `fn` as -a return type, for example. +function. But you can’t do that with closures because they don’t have a +concrete type that is returnable; you’re not allowed to use the function +pointer `fn` as a return type, for example. The following code tries to return a closure directly, but it won’t compile: @@ -124,13 +124,14 @@ it will need to store the closure. We saw a solution to this problem earlier. We can use a trait object: ```rust -fn returns_closure() -> Box i32> { +fn returns_closure() -> Box i32> { Box::new(|x| x + 1) } ``` This code will compile just fine. For more about trait objects, refer to the -“Trait Objects” section in Chapter 17. +“Using Trait Objects That Allow for Values of Different Types” section in +Chapter 17. ## Summary @@ -143,4 +144,3 @@ you to solutions. Next, we’ll put everything we’ve discussed throughout the book into practice and do one more project! - diff --git a/src/doc/book/2018-edition/src/ch20-00-final-project-a-web-server.md b/src/doc/book/2018-edition/src/ch20-00-final-project-a-web-server.md index f76d1f4c6d..990337e26a 100644 --- a/src/doc/book/2018-edition/src/ch20-00-final-project-a-web-server.md +++ b/src/doc/book/2018-edition/src/ch20-00-final-project-a-web-server.md @@ -1,34 +1,33 @@ # Final Project: Building a Multithreaded Web Server -It’s been a long journey, but here we are! The end of the book. Parting is such -sweet sorrow. But before we go, let’s build one more project together, to show -off some of the concepts we covered in these final chapters, as well as recap -some lessons from earlier. +It’s been a long journey, but we’ve reached the end of the book. In this +chapter, we’ll build one more project together to demonstrate some of the +concepts we covered in the final chapters, as well as recap some earlier +lessons. -For our final project we’re going to make a web server that only says “hello”; -which will look like Figure 20-1 in a web browser: +For our final project, we’ll make a web server that says “hello” and looks like +Figure 20-1 in a web browser. ![hello from rust](img/trpl20-01.png) -Figure 20-1: Our final shared project together +Figure 20-1: Our final shared project -Here’s the plan of how we’ll build the web server: +Here is the plan to build the web server: -1. Learn a little bit about TCP and HTTP -2. Listen for TCP connections on a socket -3. Parse a small number of HTTP requests -4. Create a proper HTTP response -5. Improve the throughput of our server with a thread pool +1. Learn a bit about TCP and HTTP. +2. Listen for TCP connections on a socket. +3. Parse a small number of HTTP requests. +4. Create a proper HTTP response. +5. Improve the throughput of our server with a thread pool. -Before we get started, however, there’s one thing we should mention: the method -we use here will not be the best way to build a web server with Rust. There are -a number of production-ready crates available on *https://crates.io* that -provide much more complete web server and thread pool implementations than we -are going to build. +But before we get started, we should mention one detail: the method we’ll use +won’t be the best way to build a web server with Rust. A number of +production-ready crates are available on *https://crates.io/* that provide more +complete web server and thread pool implementations than we’ll build. -However, for this chapter, our intention is to help you learn, not to take the -easy route. Because Rust is a systems programming language, we’re able to -choose what level of abstraction we want to work with, and can go to a lower -level than is possible or practical in other languages. We’ll therefore write -the basic HTTP server and thread pool ourselves so you can learn the general -ideas and techniques behind the crates you might use in the future. +However, our intention in this chapter is to help you learn, not to take the +easy route. Because Rust is a systems programming language, we can choose the +level of abstraction we want to work with and can go to a lower level than is +possible or practical in other languages. We’ll write the basic HTTP server and +thread pool manually so you can learn the general ideas and techniques behind +the crates you might use in the future. diff --git a/src/doc/book/2018-edition/src/ch20-01-single-threaded.md b/src/doc/book/2018-edition/src/ch20-01-single-threaded.md index 61d5082ef2..5867b47f4e 100644 --- a/src/doc/book/2018-edition/src/ch20-01-single-threaded.md +++ b/src/doc/book/2018-edition/src/ch20-01-single-threaded.md @@ -1,39 +1,39 @@ -## Building a Single Threaded Web Server +## Building a Single-Threaded Web Server -First we’ll get a single threaded web server working, but before we begin, +We’ll start by getting a single-threaded web server working. Before we begin, let’s look at a quick overview of the protocols involved in building web servers. The details of these protocols are beyond the scope of this book, but -a short overview will give you the information you need. +a brief overview will give you the information you need. The two main protocols involved in web servers are the *Hypertext Transfer -Protocol* (*HTTP*) and the *Transmission Control Protocol* (*TCP*). Both +Protocol* *(HTTP)* and the *Transmission Control Protocol* *(TCP)*. Both protocols are *request-response* protocols, meaning a *client* initiates -requests, and a *server* listens to the requests and provides a response to the +requests and a *server* listens to the requests and provides a response to the client. The contents of those requests and responses are defined by the -protocols themselves. +protocols. TCP is the lower-level protocol that describes the details of how information -gets from one server to another, but doesn’t specify what that information is. -HTTP builds on top of TCP by defining the content of the requests and +gets from one server to another but doesn’t specify what that information is. +HTTP builds on top of TCP by defining the contents of the requests and responses. It’s technically possible to use HTTP with other protocols, but in -the vast majority of cases, HTTP sends its data over TCP. We’re going to work -with the raw bytes of TCP and HTTP requests and responses. +the vast majority of cases, HTTP sends its data over TCP. We’ll work with the +raw bytes of TCP and HTTP requests and responses. ### Listening to the TCP Connection -Our web server needs to be able to listen to a TCP connection, so that’s the -first part we’ll work on. The standard library offers a `std::net` module that -lets us do this. Let’s make a new project in the usual fashion: +Our web server needs to listen to a TCP connection, so that’s the first part +we’ll work on. The standard library offers a `std::net` module that lets us do +this. Let’s make a new project in the usual fashion: ```text -$ cargo new hello --bin +$ cargo new hello Created binary (application) `hello` project $ cd hello ``` -Now enter the code in Listing 20-1 in `src/main.rs` to start. This code will +Now enter the code in Listing 20-1 in *src/main.rs* to start. This code will listen at the address `127.0.0.1:7878` for incoming TCP streams. When it gets -an incoming stream, it will print `Connection established!`: +an incoming stream, it will print `Connection established!`. Filename: src/main.rs @@ -54,64 +54,55 @@ fn main() { Listing 20-1: Listening for incoming streams and printing a message when we receive a stream -The `TcpListener` allows us to listen for TCP connections. We’ve chosen to -listen to the address `127.0.0.1:7878`. Breaking this address down, the section -before the colon is an IP address representing your own computer (this is the -same on each computer, and doesn’t represent the authors’ computer -specifically), and `7878` is the port. We’ve chosen this port for two reasons: -HTTP is normally accepted on this port and 7878 is “rust” typed on a telephone. -Note that connecting to port 80 requires administrator privileges; -non-administrators can only listen on ports higher than 1024. +Using `TcpListener`, we can listen for TCP connections at the address +`127.0.0.1:7878`. In the address, the section before the colon is an IP address +representing your computer (this is the same on every computer and doesn’t +represent the authors’ computer specifically), and `7878` is the port. We’ve +chosen this port for two reasons: HTTP is normally accepted on this port, and +7878 is *rust* typed on a telephone. -The `bind` function in this scenario works like the `new` function, in that it -will return a new `TcpListener` instance. This function is called `bind` -because, in networking, connecting to a port to listen to is known as “binding -to a port”. +The `bind` function in this scenario works like the `new` function in that it +will return a new `TcpListener` instance. The reason the function is called +`bind` is that in networking, connecting to a port to listen to is known as +“binding to a port.” The `bind` function returns a `Result`, which indicates that binding -might fail. For example, if we tried to connect to port 80 without being an -administrator, or if we ran two instances of our program and so had two -programs listening to the same port, binding wouldn’t work. Because we’re -writing a basic server for learning purposes here, we’re not going to worry -about handling these kinds of errors, so we use `unwrap` to stop the program if +might fail. For example, connecting to port 80 requires administrator +privileges (nonadministrators can listen only on ports higher than 1024), so if +we tried to connect to port 80 without being an administrator, binding wouldn’t +work. As another example, binding wouldn’t work if we ran two instances of our +program and so had two programs listening to the same port. Because we’re +writing a basic server just for learning purposes, we won’t worry about +handling these kinds of errors; instead, we use `unwrap` to stop the program if errors happen. The `incoming` method on `TcpListener` returns an iterator that gives us a sequence of streams (more specifically, streams of type `TcpStream`). A single *stream* represents an open connection between the client and the server. A -*connection* is the name for the full request/response process in which a +*connection* is the name for the full request and response process in which a client connects to the server, the server generates a response, and the server closes the connection. As such, `TcpStream` will read from itself to see what -the client sent, and allow us to write our response to the stream. Overall, +the client sent and then allow us to write our response to the stream. Overall, this `for` loop will process each connection in turn and produce a series of streams for us to handle. - - - For now, our handling of the stream consists of calling `unwrap` to terminate -our program if the stream has any errors, and if there aren’t any errors, then -print a message. We’ll add more functionality for the success case in the next -Listing. Receiving errors from the `incoming` method when a client connects to -the server is possible because we’re not actually iterating over connections, -we’re iterating over *connection attempts*. The connection might not be -successful for a number of reasons, many of them operating-system specific. For -example, many operating systems have a limit to the number of simultaneous open -connections they can support; new connection attempts beyond that number will -produce an error until some of the open connections are closed. +our program if the stream has any errors; if there aren’t any errors, the +program prints a message. We’ll add more functionality for the success case in +the next listing. The reason we might receive errors from the `incoming` method +when a client connects to the server is that we’re not actually iterating over +connections. Instead, we’re iterating over *connection attempts*. The +connection might not be successful for a number of reasons, many of them +operating system specific. For example, many operating systems have a limit to +the number of simultaneous open connections they can support; new connection +attempts beyond that number will produce an error until some of the open +connections are closed. -Let’s try this code out! First invoke `cargo run` in the terminal, then load up -`127.0.0.1:7878` in a web browser. The browser should show an error message -like “Connection reset”, because the server isn’t currently sending any data -back. If you look at your terminal, though, you should see a bunch of messages -that were printed when the browser connected to the server! +Let’s try running this code! Invoke `cargo run` in the terminal and then load +*127.0.0.1:7878* in a web browser. The browser should show an error message +like “Connection reset,” because the server isn’t currently sending back any +data. But when you look at your terminal, you should see several messages that +were printed when the browser connected to the server! ```text Running `target/debug/hello` @@ -120,9 +111,9 @@ Connection established! Connection established! ``` -Sometimes, you’ll see multiple messages printed out for one browser request; -that might be because the browser is making a request for the page as well as a -request for other resources, like the `favicon.ico` icon that appears in the +Sometimes, you’ll see multiple messages printed for one browser request; the +reason might be that the browser is making a request for the page as well as a +request for other resources, like the *favicon.ico* icon that appears in the browser tab. It could also be that the browser is trying to connect to the server multiple @@ -130,28 +121,28 @@ times because the server isn’t responding with any data. When `stream` goes ou of scope and is dropped at the end of the loop, the connection is closed as part of the `drop` implementation. Browsers sometimes deal with closed connections by retrying, because the problem might be temporary. The important -thing is that we’ve successfully gotten a handle to a TCP connection! +factor is that we’ve successfully gotten a handle to a TCP connection! -Remember to stop the program with ctrl-C when -you’re done running a particular version of the code, and restart `cargo run` -after you’ve made each set of code changes to make sure you’re running the +Remember to stop the program by pressing ctrl-c +when you’re done running a particular version of the code. Then restart `cargo +run` after you’ve made each set of code changes to make sure you’re running the newest code. ### Reading the Request -Let’s implement the functionality to read in the request from the browser! To -separate out the concerns of getting a connection and then taking some action +Let’s implement the functionality to read the request from the browser! To +separate the concerns of first getting a connection and then taking some action with the connection, we’ll start a new function for processing connections. In this new `handle_connection` function, we’ll read data from the TCP stream and -print it out so we can see the data being sent from the browser. Change the -code to look like Listing 20-2: +print it so we can see the data being sent from the browser. Change the code to +look like Listing 20-2. Filename: src/main.rs ```rust,no_run use std::io::prelude::*; -use std::net::TcpListener; use std::net::TcpStream; +use std::net::TcpListener; fn main() { let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); @@ -173,7 +164,7 @@ fn handle_connection(mut stream: TcpStream) { ``` Listing 20-2: Reading from the `TcpStream` and printing -out the data +the data We bring `std::io::prelude` into scope to get access to certain traits that let us read from and write to the stream. In the `for` loop in the `main` function, @@ -181,36 +172,30 @@ instead of printing a message that says we made a connection, we now call the new `handle_connection` function and pass the `stream` to it. In the `handle_connection` function, we’ve made the `stream` parameter mutable. -This is because the `TcpStream` instance keeps track of what data it returns to -us internally. It might read more data than we asked for and save that data for -the next time we ask for data. It therefore needs to be `mut` because its -internal state might change; usually we think of “reading” as not needing +The reason is that the `TcpStream` instance keeps track of what data it returns +to us internally. It might read more data than we asked for and save that data +for the next time we ask for data. It therefore needs to be `mut` because its +internal state might change; usually, we think of “reading” as not needing mutation, but in this case we need the `mut` keyword. - - - Next, we need to actually read from the stream. We do this in two steps: first, -we declare a `buffer` on the stack to hold the data that’s read in. We’ve made +we declare a `buffer` on the stack to hold the data that is read in. We’ve made the buffer 512 bytes in size, which is big enough to hold the data of a basic request and sufficient for our purposes in this chapter. If we wanted to handle -requests of an arbitrary size, the management of the buffer would need to be -more complicated, but we’re keeping it simple for now. We pass the buffer to -`stream.read`, which will read bytes from the `TcpStream` and put them in the -buffer. +requests of an arbitrary size, buffer management would need to be more +complicated; we’ll keep it simple for now. We pass the buffer to `stream.read`, +which will read bytes from the `TcpStream` and put them in the buffer. -We then convert the bytes in the buffer to a string and print out that string. +Second, we convert the bytes in the buffer to a string and print that string. The `String::from_utf8_lossy` function takes a `&[u8]` and produces a `String` -from it. The ‘lossy’ part of the name indicates the behavior of this function +from it. The “lossy” part of the name indicates the behavior of this function when it sees an invalid UTF-8 sequence: it will replace the invalid sequence -with �, the `U+FFFD REPLACEMENT CHARACTER`. You might see replacement +with `�`, the `U+FFFD REPLACEMENT CHARACTER`. You might see replacement characters for characters in the buffer that aren’t filled by request data. -Let’s give this a try! Start up the program and make a request in a web browser -again. Note that we’ll still get an error page in the browser, but the output -of our program in the terminal will now look similar to this: +Let’s try this code! Start the program and make a request in a web browser +again. Note that we’ll still get an error page in the browser, but our +program’s output in the terminal will now look similar to this: ```text $ cargo run @@ -229,17 +214,16 @@ Upgrade-Insecure-Requests: 1 ������������������������������������ ``` -You’ll probably get slightly different output depending on your browser. Now -that we’re printing out the request data, we can see why we get multiple -connections from one browser request by looking at the path after `Request: -GET`. If the repeated connections are all requesting `/`, we know the browser -is trying to fetch `/` repeatedly because it’s not getting a response from our -program. +Depending on your browser, you might get slightly different output. Now that +we’re printing the request data, we can see why we get multiple connections +from one browser request by looking at the path after `Request: GET`. If the +repeated connections are all requesting */*, we know the browser is trying to +fetch */* repeatedly because it’s not getting a response from our program. Let’s break down this request data to understand what the browser is asking of our program. -#### A Closer Look at an HTTP Request +### A Closer Look at an HTTP Request HTTP is a text-based protocol, and a request takes this format: @@ -249,49 +233,40 @@ headers CRLF message-body ``` -First we have the *request line* that holds information about what the client -is requesting. The first part of the request line tells us the *method* being -used, like `GET` or `POST`, that describes how the client is making this -request. Our client used a `GET` request. +The first line is the *request line* that holds information about what the +client is requesting. The first part of the request line indicates the *method* +being used, such as `GET` or `POST`, which describes how the client is making +this request. Our client used a `GET` request. - - +The next part of the request line is */*, which indicates the *Uniform Resource +Identifier* *(URI)* the client is requesting: a URI is almost, but not quite, +the same as a *Uniform Resource Locator* *(URL)*. The difference between URIs +and URLs isn’t important for our purposes in this chapter, but the HTTP spec +uses the term URI, so we can just mentally substitute URL for URI here. -The next part of the `Request` line is `/` which tells us the *URI* (Uniform -Resource Identifier) that the client is requesting---a URI is almost, but not -quite, the same as a URL (*Uniform Resource Locator*). The difference between -URIs and URLs isn’t important for our purposes of this chapter, but the HTTP -spec uses the term URI, so we can just mentally substitute URL for URI here. +The last part is the HTTP version the client uses, and then the request line +ends in a *CRLF sequence*. (CRLF stands for *carriage return* and *line feed*, +which are terms from the typewriter days!) The CRLF sequence can also be +written as `\r\n`, where `\r` is a carriage return and `\n` is a line feed. The +CRLF sequence separates the request line from the rest of the request data. +Note that when the CRLF is printed, we see a new line start rather than `\r\n`. -Finally, we’re given the HTTP version used by the client, and then the request -line ends in a CRLF sequence. The CRLF sequence can also be written as `\r\n`: -`\r` is a *carriage return* and `\n` is a *line feed*. (These terms come from -the typewriter days!) The CRLF sequence separates the request line from the -rest of the request data. Note that when CRLF is printed out, we see a new line -started rather than `\r\n`. +Looking at the request line data we received from running our program so far, +we see that `GET` is the method, */* is the request URI, and `HTTP/1.1` is the +version. - - +After the request line, the remaining lines starting from `Host:` onward are +headers. `GET` requests have no body. -Taking a look at the request line data we received rom running our program so -far, we see that `GET` is the method, `/` is the Request URI, and `HTTP/1.1` is -the version. +Try making a request from a different browser or asking for a different +address, such as *127.0.0.1:7878/test*, to see how the request data changes. -The remaining lines starting from `Host:` onward are headers; `GET` requests -have no body. - -Try making a request from a different browser, or asking for a different -address like `127.0.0.1:7878/test` to see how the request data changes, if -you’d like. - -Now that we know what the browser is asking for, let’s send some data back! +Now that we know what the browser is asking for, let’s send back some data! ### Writing a Response -We’re going to implement the sending of data in response to a client request. -Responses have the following format: +Now we’ll implement sending data in response to a client request. Responses +have the following format: ```text HTTP-Version Status-Code Reason-Phrase CRLF @@ -302,11 +277,11 @@ message-body The first line is a *status line* that contains the HTTP version used in the response, a numeric status code that summarizes the result of the request, and a reason phrase that provides a text description of the status code. After the -CRLF sequence comes any headers, another CRLF sequence, and the body of the +CRLF sequence are any headers, another CRLF sequence, and the body of the response. -Here’s an example response that uses version 1.1 of HTTP, has a status code of -`200`, a reason phrase of `OK`, no headers, and no body: +Here is an example response that uses HTTP version 1.1, has a status code of +200, an OK reason phrase, no headers, and no body: ```text HTTP/1.1 200 OK\r\n\r\n @@ -314,10 +289,9 @@ HTTP/1.1 200 OK\r\n\r\n The status code 200 is the standard success response. The text is a tiny successful HTTP response. Let’s write this to the stream as our response to a -successful request! - -From the `handle_connection` function, we need to remove the `println!` that -was printing the request data, and replace it with the code in Listing 20-3: +successful request! From the `handle_connection` function, remove the +`println!` that was printing the request data and replace it with the code in +Listing 20-3. Filename: src/main.rs @@ -339,43 +313,29 @@ fn handle_connection(mut stream: TcpStream) { Listing 20-3: Writing a tiny successful HTTP response to the stream - - -The first new line defines the `response` variable that holds the data of the -success message. Then we call `as_bytes` on our `response` to convert the -string data to bytes. The `write` method on `stream` takes a `&[u8]` and sends -those bytes directly down the connection. - - - +The first new line defines the `response` variable that holds the success +message’s data. Then we call `as_bytes` on our `response` to convert the string +data to bytes. The `write` method on `stream` takes a `&[u8]` and sends those +bytes directly down the connection. Because the `write` operation could fail, we use `unwrap` on any error result -as before. Again, in a real application you would add error-handling here. -Finally, `flush` will wait and prevent the program from continuing until all of +as before. Again, in a real application you would add error handling here. +Finally, `flush` will wait and prevent the program from continuing until all the bytes are written to the connection; `TcpStream` contains an internal -buffer to minimize calls into the underlying operating system. +buffer to minimize calls to the underlying operating system. - - - -With these changes, let’s run our code and make a request! We’re no longer +With these changes, let’s run our code and make a request. We’re no longer printing any data to the terminal, so we won’t see any output other than the -output from Cargo. Load `127.0.0.1:7878` in a web browser, though, and you -should get a blank page instead of an error. How exciting! You’ve just -hand-coded an HTTP request and response. +output from Cargo. When you load *127.0.0.1:7878* in a web browser, you should +get a blank page instead of an error. You’ve just hand-coded an HTTP request +and response! ### Returning Real HTML -Let’s implement returning more than a blank page. Create a new file, -*hello.html*, in the root of your project directory---that is, not in the `src` -directory. You can put in any HTML you want; Listing 20-4 shows one possibility: +Let’s implement the functionality for returning more than a blank page. Create +a new file, *hello.html*, in the root of your project directory, not in the +*src* directory. You can input any HTML you want; Listing 20-4 shows one +possibility. Filename: hello.html @@ -396,28 +356,24 @@ directory. You can put in any HTML you want; Listing 20-4 shows one possibility: Listing 20-4: A sample HTML file to return in a response -This is a minimal HTML 5 document with a heading and some text. To return this -from the server when a request is received, let’s modify `handle_connection` as +This is a minimal HTML5 document with a heading and some text. To return this +from the server when a request is received, we’ll modify `handle_connection` as shown in Listing 20-5 to read the HTML file, add it to the response as a body, -and send it: +and send it. Filename: src/main.rs ```rust # use std::io::prelude::*; # use std::net::TcpStream; -use std::fs::File; - +use std::fs; // --snip-- fn handle_connection(mut stream: TcpStream) { let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); - let mut file = File::open("hello.html").unwrap(); - - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string("hello.html").unwrap(); let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents); @@ -430,39 +386,39 @@ fn handle_connection(mut stream: TcpStream) { body of the response We’ve added a line at the top to bring the standard library’s `File` into -scope. The code for opening files and reading code should look familiar from -Chapter 12, when we read the contents of a file for our I/O project in Listing -12-4. +scope. The code for opening a file and reading the contents should look +familiar; we used it in Chapter 12 when we read the contents of a file for our +I/O project in Listing 12-4. -Next, we’re using `format!` to add the file’s contents as the body of the -success response. +Next, we use `format!` to add the file’s contents as the body of the success +response. -Run this code with `cargo run`, load up `127.0.0.1:7878` in your browser, and -you should see your HTML rendered! +Run this code with `cargo run` and load *127.0.0.1:7878* in your browser; you +should see your HTML rendered! -Currently we’re ignoring the request data in `buffer` and just sending back the -contents of the HTML file unconditionally. That means if you try requesting -`127.0.0.1:7878/something-else` in your browser you’ll still get back this same -HTML response. This makes for a pretty limited server and is not what most web -servers do. We’d like to customize our responses depending on the request, and -only send back the HTML file for a well-formed request to `/`. +Currently, we’re ignoring the request data in `buffer` and just sending back +the contents of the HTML file unconditionally. That means if you try requesting +*127.0.0.1:7878/something-else* in your browser, you’ll still get back this +same HTML response. Our server is very limited and is not what most web servers +do. We want to customize our responses depending on the request and only send +back the HTML file for a well-formed request to */*. ### Validating the Request and Selectively Responding Right now, our web server will return the HTML in the file no matter what the client requested. Let’s add functionality to check that the browser is -requesting `/` before returning the HTML file, and return an error if the -browser requests anything else. For this we need to modify `handle_connection` +requesting */* before returning the HTML file and return an error if the +browser requests anything else. For this we need to modify `handle_connection`, as shown in Listing 20-6. This new code checks the content of the request -received against what we know a request for `/` looks like and adds `if` and -`else` blocks to treat requests differently: +received against what we know a request for */* looks like and adds `if` and +`else` blocks to treat requests differently. Filename: src/main.rs ```rust # use std::io::prelude::*; # use std::net::TcpStream; -# use std::fs::File; +# use std::fs; // --snip-- fn handle_connection(mut stream: TcpStream) { @@ -472,10 +428,7 @@ fn handle_connection(mut stream: TcpStream) { let get = b"GET / HTTP/1.1\r\n"; if buffer.starts_with(get) { - let mut file = File::open("hello.html").unwrap(); - - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string("hello.html").unwrap(); let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents); @@ -488,13 +441,13 @@ fn handle_connection(mut stream: TcpStream) { ``` Listing 20-6: Matching the request and handling requests -to `/` differently than other requests +to */* differently than other requests -First, we hardcode the data corresponding to the `/` request into the `get` +First, we hardcode the data corresponding to the */* request into the `get` variable. Because we’re reading raw bytes into the buffer, we transform `get` into a byte string by adding the `b""` byte string syntax at the start of the -content data. Then, we check to see if `buffer` starts with the bytes in `get`. -If it does, it means we’ve received a well-formed request to `/`, which is the +content data. Then we check whether `buffer` starts with the bytes in `get`. If +it does, it means we’ve received a well-formed request to */*, which is the success case we’ll handle in the `if` block that returns the contents of our HTML file. @@ -502,32 +455,29 @@ If `buffer` does *not* start with the bytes in `get`, it means we’ve received some other request. We’ll add code to the `else` block in a moment to respond to all other requests. -Run this code now and request `127.0.0.1:7878`, and you should get the HTML in +Run this code now and request *127.0.0.1:7878*; you should get the HTML in *hello.html*. If you make any other request, such as -`127.0.0.1:7878/something-else`, you’ll get a connection error like we saw when -running the code in Listing 20-1 and Listing 20-2. +*127.0.0.1:7878/something-else*, you’ll get a connection error like those you +saw when running the code in Listing 20-1 and Listing 20-2. Now let’s add the code in Listing 20-7 to the `else` block to return a response -with the status code `404`, which signals that the content for the request was +with the status code 404, which signals that the content for the request was not found. We’ll also return some HTML for a page to render in the browser -indicating as such to the end user: +indicating the response to the end user. Filename: src/main.rs ```rust # use std::io::prelude::*; # use std::net::TcpStream; -# use std::fs::File; +# use std::fs; # fn handle_connection(mut stream: TcpStream) { # if true { // --snip-- } else { let status_line = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; - let mut file = File::open("404.html").unwrap(); - let mut contents = String::new(); - - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string("404.html").unwrap(); let response = format!("{}{}", status_line, contents); @@ -537,14 +487,14 @@ indicating as such to the end user: # } ``` -Listing 20-7: Responding with status code `404` and an -error page if anything other than `/` was requested +Listing 20-7: Responding with status code 404 and an +error page if anything other than */* was requested -Here, our response has a status line with status code `404` and the reason +Here, our response has a status line with status code 404 and the reason phrase `NOT FOUND`. We’re still not returning headers, and the body of the response will be the HTML in the file *404.html*. You’ll need to create a *404.html* file next to *hello.html* for the error page; again feel free to use -any HTML you’d like or use the example HTML in Listing 20-8: +any HTML you want or use the example HTML in Listing 20-8. Filename: 404.html @@ -563,29 +513,29 @@ any HTML you’d like or use the example HTML in Listing 20-8: ``` Listing 20-8: Sample content for the page to send back -with any `404` response +with any 404 response -With these changes, try running your server again. Requesting `127.0.0.1:7878` +With these changes, run your server again. Requesting *127.0.0.1:7878* should return the contents of *hello.html*, and any other request, like -`127.0.0.1:7878/foo`, should return the error HTML from *404.html*! +*127.0.0.1:7878/foo*, should return the error HTML from *404.html*. ### A Touch of Refactoring -At the moment our `if` and `else` blocks have a lot of repetition: they’re both +At the moment the `if` and `else` blocks have a lot of repetition: they’re both reading files and writing the contents of the files to the stream. The only -differences are the status line and the filename. Let’s make our code more -concise by pulling those differences out into an `if` and `else` of one line -each that will assign the values of the status line and the filename to -variables; we can then use those variables unconditionally in the code to read -the file and write the response. The resulting code after replacing the large -`if` and `else` blocks is shown in Listing 20-9: +differences are the status line and the filename. Let’s make the code more +concise by pulling out those differences into separate `if` and `else` lines +that will assign the values of the status line and the filename to variables; +we can then use those variables unconditionally in the code to read the file +and write the response. Listing 20-9 shows the resulting code after replacing +the large `if` and `else` blocks. Filename: src/main.rs ```rust # use std::io::prelude::*; # use std::net::TcpStream; -# use std::fs::File; +# use std::fs; // --snip-- fn handle_connection(mut stream: TcpStream) { @@ -601,10 +551,7 @@ fn handle_connection(mut stream: TcpStream) { ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html") }; - let mut file = File::open(filename).unwrap(); - let mut contents = String::new(); - - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string(filename).unwrap(); let response = format!("{}{}", status_line, contents); @@ -613,25 +560,26 @@ fn handle_connection(mut stream: TcpStream) { } ``` -Listing 20-9: Refactoring so that the `if` and `else` -blocks only contain the code that differs between the two cases +Listing 20-9: Refactoring the `if` and `else` blocks to +contain only the code that differs between the two cases Now the `if` and `else` blocks only return the appropriate values for the status line and filename in a tuple; we then use destructuring to assign these two values to `status_line` and `filename` using a pattern in the `let` -statement like we discussed in Chapter 18. +statement, as discussed in Chapter 18. The previously duplicated code is now outside the `if` and `else` blocks and uses the `status_line` and `filename` variables. This makes it easier to see -exactly what’s different between the two cases, and means we have only one -place to update the code if we want to change how the file reading and response -writing works. The behavior of the code in Listing 20-9 will be exactly the -same as that in Listing 20-8. +the difference between the two cases, and it means we have only one place to +update the code if we want to change how the file reading and response writing +work. The behavior of the code in Listing 20-9 will be the same as that in +Listing 20-8. -Awesome! We have a simple little web server in about 40 lines of Rust code that -responds to one request with a page of content and responds to all other -requests with a `404` response. +Awesome! We now have a simple web server in approximately 40 lines of Rust code +that responds to one request with a page of content and responds to all other +requests with a 404 response. -Currently our server runs in a single thread, meaning it can only serve one -request at a time. Let’s see how that can be a problem by simulating some slow -requests, and then fix it so our server can handle multiple requests at once. +Currently, our server runs in a single thread, meaning it can only serve one +request at a time. Let’s examine how that can be a problem by simulating some +slow requests. Then we’ll fix it so our server can handle multiple requests at +once. diff --git a/src/doc/book/2018-edition/src/ch20-02-multithreaded.md b/src/doc/book/2018-edition/src/ch20-02-multithreaded.md index b6fc41830f..ff6986926c 100644 --- a/src/doc/book/2018-edition/src/ch20-02-multithreaded.md +++ b/src/doc/book/2018-edition/src/ch20-02-multithreaded.md @@ -1,24 +1,19 @@ -## Turning our Single Threaded Server into a Multithreaded Server - - - +## Turning Our Single-Threaded Server into a Multithreaded Server Right now, the server will process each request in turn, meaning it won’t -process a second connection until the first is finished processing. If this -server were to receive more and more requests, this sort of serial execution -would prove to be less and less optimal. If the server receives a request that -takes a long time to process, subsequent requests will have to wait until the -long request is finished, even if the new requests can be processed quickly. -We’ll need to fix this, but first, we’ll look at the problem in action. +process a second connection until the first is finished processing. If the +server received more and more requests, this serial execution would be less and +less optimal. If the server receives a request that takes a long time to +process, subsequent requests will have to wait until the long request is +finished, even if the new requests can be processed quickly. We’ll need to fix +this, but first, we’ll look at the problem in action. ### Simulating a Slow Request in the Current Server Implementation -Let’s see how a slow-processing request can affect other requests made to our -current server implementation. Listing 20-10 implements handling a request to -`/sleep` with a simulated slow response that will cause the server to sleep for -five seconds before responding. +We’ll look at how a slow-processing request can affect other requests made to +our current server implementation. Listing 20-10 implements handling a request +to */sleep* with a simulated slow response that will cause the server to sleep +for 5 seconds before responding. Filename: src/main.rs @@ -52,83 +47,79 @@ fn handle_connection(mut stream: TcpStream) { ``` Listing 20-10: Simulating a slow request by recognizing -`/sleep` and sleeping for 5 seconds +*/sleep* and sleeping for 5 seconds -This code is a bit messy, but it’s good enough for our simulation purposes! We +This code is a bit messy, but it’s good enough for simulation purposes. We created a second request `sleep`, whose data our server recognizes. We added an -`else if` after the `if` block to check for the request to `/sleep`, and when -that request is received, our server will sleep for five seconds before -rendering the successful HTML page. +`else if` after the `if` block to check for the request to */sleep*. When that +request is received, the server will sleep for 5 seconds before rendering the +successful HTML page. -You can really see how primitive our server is here; real libraries would -handle the recognition of multiple requests in a much less verbose way! +You can see how primitive our server is: real libraries would handle the +recognition of multiple requests in a much less verbose way! -Start the server with `cargo run`, and then open up two browser windows: one -for `http://localhost:7878/` and one for `http://localhost:7878/sleep`. If you -enter the `/` URI a few times, as before, you’ll see it respond quickly. But if -you enter `/sleep`, and then load up `/`, you’ll see that `/` waits until -`sleep` has slept for its full five seconds before loading. +Start the server using `cargo run`. Then open two browser windows: one for +*http://127.0.0.1:7878/* and the other for *http://127.0.0.1:7878/sleep*. If +you enter the */* URI a few times, as before, you’ll see it respond quickly. +But if you enter */sleep* and then load */*, you’ll see that */* waits until +`sleep` has slept for its full 5 seconds before loading. -There are multiple ways we could change how our web server works in order to -avoid having all requests back up behind a slow request; the one we’re going to -implement is a thread pool. +There are multiple ways we could change how our web server works to avoid +having more requests back up behind a slow request; the one we’ll implement is +a thread pool. ### Improving Throughput with a Thread Pool - - - A *thread pool* is a group of spawned threads that are waiting and ready to -handle some task. When the program receives a new task, it will assign one of -the threads in the pool to the task, and that thread will go off and process -the task. The remaining threads in the pool are available to handle any other -tasks that come in while the first thread is processing. When the first thread -is done processing its task, it’s returned to the pool of idle threads ready to -handle a new task. A thread pool will allow us to process connections -concurrently, increasing the throughput of our server. +handle a task. When the program receives a new task, it assigns one of the +threads in the pool to the task, and that thread will process the task. The +remaining threads in the pool are available to handle any other tasks that come +in while the first thread is processing. When the first thread is done +processing its task, it’s returned to the pool of idle threads, ready to handle +a new task. A thread pool allows you to process connections concurrently, +increasing the throughput of your server. We’ll limit the number of threads in the pool to a small number to protect us from Denial of Service (DoS) attacks; if we had our program create a new thread -for each request as it comes in, someone making ten million requests to our -server could create havoc by using up all of our server’s resources and -grinding the processing of all requests to a halt. +for each request as it came in, someone making 10 million requests to our +server could create havoc by using up all our server’s resources and grinding +the processing of requests to a halt. -Rather than spawning unlimited threads, then, we’ll have a fixed number of -threads waiting in the pool. As requests come in, they’ll be sent to the pool -for processing. The pool will maintain a queue of incoming requests. Each of -the threads in the pool will pop a request off of this queue, handle the -request, and then ask the queue for another request. With this design, we can -process `N` requests concurrently, where `N` is the number of threads. If each -thread is responding to a long-running request, subsequent requests can still -back up in the queue, but we’ve increased the number of long-running requests -we can handle before that point. +Rather than spawning unlimited threads, we’ll have a fixed number of threads +waiting in the pool. As requests come in, they’ll be sent to the pool for +processing. The pool will maintain a queue of incoming requests. Each of the +threads in the pool will pop off a request from this queue, handle the request, +and then ask the queue for another request. With this design, we can process +`N` requests concurrently, where `N` is the number of threads. If each thread +is responding to a long-running request, subsequent requests can still back up +in the queue, but we’ve increased the number of long-running requests we can +handle before reaching that point. -This is just one of many ways to improve the throughput of our web server. -Other options you might explore are the fork/join model and the single threaded -async I/O model. If you’re interested in this topic, you may want to read more -about other solutions and try to implement them in Rust; with a low-level -language like Rust, all of these options are possible. +This technique is just one of many ways to improve the throughput of a web +server. Other options you might explore are the fork/join model and the +single-threaded async I/O model. If you’re interested in this topic, you can +read more about other solutions and try to implement them in Rust; with a +low-level language like Rust, all of these options are possible. -Before we begin, let’s talk about what using the pool should look like. When -trying to design code, writing the client interface first can really help guide -your design. Write the API of the code so that it’s structured in the way you’d -want to call it, then implement the functionality within that structure, rather -than implementing the functionality then designing the public API. +Before we begin implementing a thread pool, let’s talk about what using the +pool should look like. When you’re trying to design code, writing the client +interface first can help guide your design. Write the API of the code so it’s +structured in the way you want to call it; then implement the functionality +within that structure rather than implementing the functionality and then +designing the public API. -Similar to how we used Test Driven Development in the project in Chapter 12, -we’re going to use Compiler Driven Development here. We’ll write the code that -calls the functions we wish we had, then we’ll look at errors from the compiler -to tell us what we should change next to get things working. +Similar to how we used test-driven development in the project in Chapter 12, +we’ll use compiler-driven development here. We’ll write the code that calls the +functions we want, and then we’ll look at errors from the compiler to determine +what we should change next to get the code to work. -#### Code Structure if We Could Spawn a Thread for Each Request +#### Code Structure If We Could Spawn a Thread for Each Request First, let’s explore how our code might look if it did create a new thread for -every connection. As mentioned, this isn’t our final plan due to the problems -with potentially spawning an unlimited number of threads, but it’s a starting -point. Listing 20-11 shows the changes to make to `main` to spawn a new thread -to handle each stream within the `for` loop: +every connection. As mentioned earlier, this isn’t our final plan due to the +problems with potentially spawning an unlimited number of threads, but it is a +starting point. Listing 20-11 shows the changes to make to `main` to spawn a +new thread to handle each stream within the `for` loop. Filename: src/main.rs @@ -155,19 +146,19 @@ fn main() { Listing 20-11: Spawning a new thread for each stream -As we learned in Chapter 16, `thread::spawn` will create a new thread and then +As you learned in Chapter 16, `thread::spawn` will create a new thread and then run the code in the closure in the new thread. If you run this code and load -`/sleep` in your browser, then `/` in two more browser tabs, you’ll indeed see -the requests to `/` don’t have to wait for `/sleep` to finish. But as we -mentioned, this will eventually overwhelm the system because we’re making new -threads without any limit. +*/sleep* in your browser, then */* in two more browser tabs, you’ll indeed see +that the requests to */* don’t have to wait for */sleep* to finish. But as we +mentioned, this will eventually overwhelm the system because you’d be making +new threads without any limit. #### Creating a Similar Interface for a Finite Number of Threads -We want our thread pool to work in a similar, familiar way so that switching -from threads to a thread pool doesn’t require large changes to the code using +We want our thread pool to work in a similar, familiar way so switching from +threads to a thread pool doesn’t require large changes to the code that uses our API. Listing 20-12 shows the hypothetical interface for a `ThreadPool` -struct we’d like to use instead of `thread::spawn`: +struct we want to use instead of `thread::spawn`. Filename: src/main.rs @@ -202,21 +193,16 @@ fn main() { We use `ThreadPool::new` to create a new thread pool with a configurable number of threads, in this case four. Then, in the `for` loop, `pool.execute` has a -similar interface as `thread::spawn`, in that it takes a closure of what code -the pool should run for each stream. We need to implement `pool.execute` such -that it takes the closure and gives it to a thread in the pool to run. This -code won’t yet compile, but we’re going to try so the compiler can guide us in -how to fix it. - - - +similar interface as `thread::spawn` in that it takes a closure the pool should +run for each stream. We need to implement `pool.execute` so it takes the +closure and gives it to a thread in the pool to run. This code won’t yet +compile, but we’ll try so the compiler can guide us in how to fix it. #### Building the `ThreadPool` Struct Using Compiler Driven Development -Go ahead and make the changes in Listing 20-12 to *src/main.rs*, and let’s use -the compiler errors from `cargo check` to drive our development. Here’s the -first error we get: +Make the changes in Listing 20-12 to *src/main.rs*, and then let’s use the +compiler errors from `cargo check` to drive our development. Here is the first +error we get: ```text $ cargo check @@ -231,15 +217,16 @@ error[E0433]: failed to resolve. Use of undeclared type or module `ThreadPool` error: aborting due to previous error ``` -Great, this is telling us we need a `ThreadPool` type or module, so we’ll build -one now. Our `ThreadPool` implementation will be independent of the kind of -work our web server is doing, so let’s switch the `hello` crate from a binary -crate to a library crate to hold our `ThreadPool` implementation. This also -means we could use the separate thread pool library for whatever work we want -to do, not just for serving web requests. +Great! This error tells us we need a `ThreadPool` type or module, so we’ll +build one now. Our `ThreadPool` implementation will be independent of the kind +of work our web server is doing. So, let’s switch the `hello` crate from a +binary crate to a library crate to hold our `ThreadPool` implementation. After +we change to a library crate, we could also use the separate thread pool +library for any work we want to do using a thread pool, not just for serving +web requests. -Create a *src/lib.rs* that contains the following, which is simplest definition -of a `ThreadPool` struct that we can have for now: +Create a *src/lib.rs* that contains the following, which is the simplest +definition of a `ThreadPool` struct that we can have for now: Filename: src/lib.rs @@ -248,11 +235,11 @@ pub struct ThreadPool; ``` Then create a new directory, *src/bin*, and move the binary crate rooted in -*src/main.rs* into *src/bin/main.rs*. This will make the library crate the +*src/main.rs* into *src/bin/main.rs*. Doing so will make the library crate the primary crate in the *hello* directory; we can still run the binary in -*src/bin/main.rs* using `cargo run` though. After moving the *main.rs* file, -edit it to bring the library crate in and bring `ThreadPool` into scope by -adding the following code to the top of *src/bin/main.rs*: +*src/bin/main.rs* using `cargo run`. After moving the *main.rs* file, edit it +to bring the library crate in and bring `ThreadPool` into scope by adding the +following code to the top of *src/bin/main.rs*: Filename: src/bin/main.rs @@ -261,8 +248,8 @@ extern crate hello; use hello::ThreadPool; ``` -This still won’t work, but let’s try checking it again in order to get the next -error that we need to address: +This code still won’t work, but let’s check it again to get the next error that +we need to address: ```text $ cargo check @@ -276,9 +263,9 @@ error[E0599]: no function or associated item named `new` found for type `hello::ThreadPool` ``` -Cool, this tells us that next we need to create an associated function named +This error indicates that next we need to create an associated function named `new` for `ThreadPool`. We also know that `new` needs to have one parameter -that can accept `4` as an argument, and should return a `ThreadPool` instance. +that can accept `4` as an argument and should return a `ThreadPool` instance. Let’s implement the simplest `new` function that will have those characteristics: @@ -294,8 +281,8 @@ impl ThreadPool { } ``` -We picked `usize` as the type of the `size` parameter, because we know that a -negative number of threads makes no sense. We also know we’re going to use this +We chose `usize` as the type of the `size` parameter, because we know that a +negative number of threads doesn’t make any sense. We also know we’ll use this 4 as the number of elements in a collection of threads, which is what the `usize` type is for, as discussed in the “Integer Types” section of Chapter 3. @@ -320,30 +307,21 @@ error[E0599]: no method named `execute` found for type `hello::ThreadPool` in th | ^^^^^^^ ``` - - - Now we get a warning and an error. Ignoring the warning for a moment, the error occurs because we don’t have an `execute` method on `ThreadPool`. Recall from the “Creating a Similar Interface for a Finite Number of Threads” section that -we decided our thread pool should have an interface similar to that of -`thread::spawn`, and that we’re going to implement the `execute` function to -take the closure that it’s given and give it to an idle thread in the pool to -run. +we decided our thread pool should have an interface similar to `thread::spawn`. +In addition, we’ll implement the `execute` function so it takes the closure +it’s given and gives it to an idle thread in the pool to run. We’ll define the `execute` method on `ThreadPool` to take a closure as a -parameter. If you remember from the “Storing Closures Using Generic Parameters -and the `Fn` Traits” section in Chapter 13, we can take closures as parameters -with three different traits: `Fn`, `FnMut`, and `FnOnce`. We need to decide -which kind of closure to use here. We know we’re going to end up doing -something similar to the standard library `thread::spawn` implementation, so we -can look at what bounds the signature of `thread::spawn` has on its parameter. -The documentation tells us: +parameter. Recall from the “Storing Closures Using Generic Parameters and the +`Fn` Traits” section in Chapter 13 that we can take closures as parameters with +three different traits: `Fn`, `FnMut`, and `FnOnce`. We need to decide which +kind of closure to use here. We know we’ll end up doing something similar to +the standard library `thread::spawn` implementation, so we can look at what +bounds the signature of `thread::spawn` has on its parameter. The documentation +shows us the following: ```rust,ignore pub fn spawn(f: F) -> JoinHandle @@ -352,24 +330,19 @@ pub fn spawn(f: F) -> JoinHandle T: Send + 'static ``` -`F` is the parameter we care about here; `T` is related to the return value and -we’re not concerned with that. We can see that `spawn` uses `FnOnce` as the -trait bound on `F`. This is probably what we want as well, because we’ll -eventually be passing the argument we get in `execute` to `spawn`. We can be -further confident that `FnOnce` is the trait we want to use because the thread -for running a request is only going to execute that request’s closure one time, -which matches the `Once` in `FnOnce`. +The `F` type parameter is the one we’re concerned with here; the `T` type +parameter is related to the return value, and we’re not concerned with that. We +can see that `spawn` uses `FnOnce` as the trait bound on `F`. This is probably +what we want as well, because we’ll eventually pass the argument we get in +`execute` to `spawn`. We can be further confident that `FnOnce` is the trait we +want to use because the thread for running a request will only execute that +request’s closure one time, which matches the `Once` in `FnOnce`. - - - -`F` also has the trait bound `Send` and the lifetime bound `'static`, which are -useful for our situation: we need `Send` to transfer the closure from one -thread to another, and `'static` because we don’t know how long the thread will -take to execute. Let’s create an `execute` method on `ThreadPool` that will -take a generic parameter `F` with these bounds: +The `F` type parameter also has the trait bound `Send` and the lifetime bound +`'static`, which are useful in our situation: we need `Send` to transfer the +closure from one thread to another and `'static` because we don’t know how long +the thread will take to execute. Let’s create an `execute` method on +`ThreadPool` that will take a generic parameter of type `F` with these bounds: Filename: src/lib.rs @@ -387,13 +360,13 @@ impl ThreadPool { } ``` -We still use the `()` after `FnOnce` because this `FnOnce` is representing a -closure that takes no parameters and doesn’t return a value. Just like function +We still use the `()` after `FnOnce` because this `FnOnce` represents a closure +that takes no parameters and doesn’t return a value. Just like function definitions, the return type can be omitted from the signature, but even if we have no parameters, we still need the parentheses. -Again, we’ll add the simplest implementation of the `execute` method, which -does nothing, just to get our code compiling. Let’s check it again: +Again, this is the simplest implementation of the `execute` method: it does +nothing, but we’re trying only to make our code compile. Let’s check it again: ```text $ cargo check @@ -416,30 +389,29 @@ warning: unused variable: `f` = note: to avoid this warning, consider using `_f` instead ``` -We’re receiving only warnings now! That means it compiles! Note, though, that -if you try `cargo run` and make a request in the browser, you’ll see the errors -in the browser that we saw in the beginning of the chapter. Our library isn’t +We’re receiving only warnings now, which means it compiles! But note that if +you try `cargo run` and make a request in the browser, you’ll see the errors in +the browser that we saw at the beginning of the chapter. Our library isn’t actually calling the closure passed to `execute` yet! -> A saying you might hear about languages with strict compilers like Haskell -> and Rust is “if the code compiles, it works.” This is a good time to remember -> that this is not actually universally true. Our project compiles, but it does -> absolutely nothing! If we were building a real, complete project, this would -> be a great time to start writing unit tests to check that the code compiles -> *and* has the behavior we want. +> Note: A saying you might hear about languages with strict compilers, such as +> Haskell and Rust, is “if the code compiles, it works.” But this saying is not +> universally true. Our project compiles, but it does absolutely nothing! If we +> were building a real, complete project, this would be a good time to start +> writing unit tests to check that the code compiles *and* has the behavior we +> want. #### Validating the Number of Threads in `new` -We’re still getting warnings because we aren’t doing anything with the +We’ll continue to get warnings because we aren’t doing anything with the parameters to `new` and `execute`. Let’s implement the bodies of these -functions with the behavior we want. To start, let’s think about `new`. - -Earlier we chose an unsigned type for the `size` parameter, because a pool with -a negative number of threads makes no sense. However, a pool with zero threads -also makes no sense, yet zero is a perfectly valid `usize`. Let’s add code to -check that `size` is greater than zero before we return a `ThreadPool` -instance, and have the program panic if a zero is received by using the -`assert!` macro as shown in Listing 20-13: +functions with the behavior we want. To start, let’s think about `new`. Earlier +we chose an unsigned type for the `size` parameter, because a pool with a +negative number of threads makes no sense. However, a pool with zero threads +also makes no sense, yet zero is a perfectly valid `usize`. We’ll add code to +check that `size` is greater than zero before we return a `ThreadPool` instance +and have the program panic if it receives a zero by using the `assert!` macro, +as shown in Listing 20-13. Filename: src/lib.rs @@ -466,31 +438,29 @@ impl ThreadPool { Listing 20-13: Implementing `ThreadPool::new` to panic if `size` is zero -We’ve taken this opportunity to add some documentation for our `ThreadPool` -with doc comments. Note that we followed good documentation practices by adding -a section that calls out the situations in which our function can panic as we -discussed in Chapter 14. Try running `cargo doc --open` and clicking on the -`ThreadPool` struct to see what the generate docs for `new` look like! +We’ve added some documentation for our `ThreadPool` with doc comments. Note +that we followed good documentation practices by adding a section that calls +out the situations in which our function can panic, as discussed in Chapter 14. +Try running `cargo doc --open` and clicking the `ThreadPool` struct to see what +the generated docs for `new` look like! Instead of adding the `assert!` macro as we’ve done here, we could make `new` return a `Result` like we did with `Config::new` in the I/O project in Listing -12-9, but we’ve decided in this case that trying to create a thread pool +12-9. But we’ve decided in this case that trying to create a thread pool without any threads should be an unrecoverable error. If you’re feeling -ambitious, try to write a version of `new` with this signature to see how you -feel about both versions: +ambitious, try to write a version of `new` with the following signature to +compare both versions: ```rust,ignore -fn new(size: usize) -> Result { +pub fn new(size: usize) -> Result { ``` #### Creating Space to Store the Threads Now that we have a way to know we have a valid number of threads to store in -the pool, we can actually create those threads and store them in the -`ThreadPool` struct before returning it. - -This raises a question: how do we “store” a thread? Let’s take another look at -the signature of `thread::spawn`: +the pool, we can create those threads and store them in the `ThreadPool` struct +before returning it. But how do we “store” a thread? Let’s take another look at +the `thread::spawn` signature: ```rust,ignore pub fn spawn(f: F) -> JoinHandle @@ -499,16 +469,16 @@ pub fn spawn(f: F) -> JoinHandle T: Send + 'static ``` -`spawn` returns a `JoinHandle`, where `T` is the type that’s returned from -the closure. Let’s try using `JoinHandle` too and see what happens. In our +The `spawn` function returns a `JoinHandle`, where `T` is the type that the +closure returns. Let’s try using `JoinHandle` too and see what happens. In our case, the closures we’re passing to the thread pool will handle the connection and not return anything, so `T` will be the unit type `()`. -The code in Listing 20-14 will compile, but isn’t actually creating any threads -yet. We’ve changed the definition of `ThreadPool` to hold a vector of +The code in Listing 20-14 will compile but doesn’t create any threads yet. +We’ve changed the definition of `ThreadPool` to hold a vector of `thread::JoinHandle<()>` instances, initialized the vector with a capacity of `size`, set up a `for` loop that will run some code to create the threads, and -returned a `ThreadPool` instance containing them: +returned a `ThreadPool` instance containing them. Filename: src/lib.rs @@ -542,78 +512,62 @@ impl ThreadPool { Listing 20-14: Creating a vector for `ThreadPool` to hold the threads -We’ve brought `std::thread` into scope in the library crate, because we’re using -`thread::JoinHandle` as the type of the items in the vector in `ThreadPool`. +We’ve brought `std::thread` into scope in the library crate, because we’re +using `thread::JoinHandle` as the type of the items in the vector in +`ThreadPool`. Once a valid size is received, our `ThreadPool` creates a new vector that can hold `size` items. We haven’t used the `with_capacity` function in this book -yet, which does the same thing as `Vec::new`, but with an important difference: -it pre-allocates space in the vector. Because we know that we need to store -`size` elements in the vector, doing this allocation up-front is slightly more -efficient than using `Vec::new`, which resizes itself as elements get inserted. +yet, which performs the same task as `Vec::new` but with an important +difference: it preallocates space in the vector. Because we know we need to +store `size` elements in the vector, doing this allocation up front is slightly +more efficient than using `Vec::new`, which resizes itself as elements are +inserted. -If you run `cargo check` again, you’ll get a few more warnings, but it should +When you run `cargo check` again, you’ll get a few more warnings, but it should succeed. #### A `Worker` Struct Responsible for Sending Code from the `ThreadPool` to a Thread - - - We left a comment in the `for` loop in Listing 20-14 regarding the creation of -threads. How do we actually create threads? This is a tough question. The way -to create a thread provided by the standard library, `thread::spawn`, expects -to get some code that the thread should run as soon as the thread is created. -However, we want to start up the threads and have them wait for code that we -will send them later. The standard library’s implementation of threads doesn’t -include any way to do that; we have to implement it. +threads. Here, we’ll look at how we actually create threads. The standard +library provides `thread::spawn` as a way to create threads, and +`thread::spawn` expects to get some code the thread should run as soon as the +thread is created. However, in our case, we want to create the threads and have +them *wait* for code that we’ll send later. The standard library’s +implementation of threads doesn’t include any way to do that; we have to +implement it manually. - - - -The way we’re going to implement the behavior of creating threads and sending -code later is to introduce a new data structure between the `ThreadPool` and -the threads that will manage this new behavior. We’re going to call this data -structure `Worker`; this is a common term in pooling implementations. Think of -people working in the kitchen at a restaurant: the workers wait until orders -come in from customers, then they’re responsible for taking those orders and -fulfilling them. - - - +We’ll implement this behavior by introducing a new data structure between the +`ThreadPool` and the threads that will manage this new behavior. We’ll call +this data structure `Worker`, which is a common term in pooling +implementations. Think of people working in the kitchen at a restaurant: the +workers wait until orders come in from customers, and then they’re responsible +for taking those orders and filling them. Instead of storing a vector of `JoinHandle<()>` instances in the thread pool, we’ll store instances of the `Worker` struct. Each `Worker` will store a single `JoinHandle<()>` instance. Then we’ll implement a method on `Worker` that will -take a closure of code to run and send it to the already-running thread for -execution. We’ll also give each worker an `id` so we can tell the different -workers in the pool apart when logging or debugging. +take a closure of code to run and send it to the already running thread for +execution. We’ll also give each worker an `id` so we can distinguish between +the different workers in the pool when logging or debugging. -First, let’s make these changes to what happens when we create a `ThreadPool`. +Let’s make the following changes to what happens when we create a `ThreadPool`. We’ll implement the code that sends the closure to the thread after we have `Worker` set up in this way: -1. Define a `Worker` struct that holds an `id` and a `JoinHandle<()>` -2. Change `ThreadPool` to hold a vector of `Worker` instances +1. Define a `Worker` struct that holds an `id` and a `JoinHandle<()>`. +2. Change `ThreadPool` to hold a vector of `Worker` instances. 3. Define a `Worker::new` function that takes an `id` number and returns a - `Worker` instance that holds the allocated `id` and a thread spawned with an - empty closure + `Worker` instance that holds the `id` and a thread spawned with an empty + closure. 4. In `ThreadPool::new`, use the `for` loop counter to generate an `id`, create - a new `Worker` with that `id`, and store the worker in the vector + a new `Worker` with that `id`, and store the worker in the vector. If you’re up for a challenge, try implementing these changes on your own before -taking a look at the code in Listing 20-15. +looking at the code in Listing 20-15. -Ready? Here’s Listing 20-15 with one way to make these modifications: +Ready? Here is Listing 20-15 with one way to make the preceding modifications. Filename: src/lib.rs @@ -671,30 +625,30 @@ External code (like our server in *src/bin/main.rs*) doesn’t need to know the implementation details regarding using a `Worker` struct within `ThreadPool`, so we make the `Worker` struct and its `new` function private. The `Worker::new` function uses the `id` we give it and stores a `JoinHandle<()>` -instance that’s created by spawning a new thread using an empty closure. +instance that is created by spawning a new thread using an empty closure. -This code will compile and and will store the number of `Worker` instances we -specified as an argument to `ThreadPool::new`, but we’re *still* not processing -the closure that we get in `execute`. Let’s talk about how to do that next. +This code will compile and will store the number of `Worker` instances we +specified as an argument to `ThreadPool::new`. But we’re *still* not processing +the closure that we get in `execute`. Let’s look at how to do that next. -#### Sending Requests to Threads Via Channels +#### Sending Requests to Threads via Channels -The next problem to tackle is that the closures given to `thread::spawn` do +Now we’ll tackle the problem that the closures given to `thread::spawn` do absolutely nothing. Currently, we get the closure we want to execute in the -`execute` method, but we need to give `thread::spawn` a closure to run when we +`execute` method. But we need to give `thread::spawn` a closure to run when we create each `Worker` during the creation of the `ThreadPool`. We want the `Worker` structs that we just created to fetch code to run from a -queue held in the `ThreadPool`, and send that code to its thread to run. +queue held in the `ThreadPool` and send that code to its thread to run. -In Chapter 16, we learned about *channels*---a simple way to communicate -between two threads---that would be perfect for this use-case. We’ll use a -channel to function as the queue of jobs, and `execute` will send a job from -the `ThreadPool` to the `Worker` instances, which will send the job to its -thread. Here’s the plan: +In Chapter 16, you learned about *channels*—a simple way to communicate between +two threads—that would be perfect for this use case. We’ll use a channel to +function as the queue of jobs, and `execute` will send a job from the +`ThreadPool` to the `Worker` instances, which will send the job to its thread. +Here is the plan: -1. `ThreadPool` will create a channel and hold on to the sending side of the - channel. +1. The `ThreadPool` will create a channel and hold on to the sending side of + the channel. 2. Each `Worker` will hold on to the receiving side of the channel. 3. We’ll create a new `Job` struct that will hold the closures we want to send down the channel. @@ -704,9 +658,9 @@ thread. Here’s the plan: and execute the closures of any jobs it receives. Let’s start by creating a channel in `ThreadPool::new` and holding the sending -side in the `ThreadPool` instance, as shown in Listing 20-16. `Job` is a struct -that doesn’t hold anything for now, but will be the type of item we’re sending -down the channel: +side in the `ThreadPool` instance, as shown in Listing 20-16. The `Job` struct +doesn’t hold anything for now but will be the type of item we’re sending down +the channel. Filename: src/lib.rs @@ -763,13 +717,13 @@ impl ThreadPool { Listing 20-16: Modifying `ThreadPool` to store the sending end of a channel that sends `Job` instances -In `ThreadPool::new`, we create our new channel, and have the pool hold the +In `ThreadPool::new`, we create our new channel and have the pool hold the sending end. This will successfully compile, still with warnings. Let’s try passing a receiving end of the channel into each worker as the thread -pool creates them. We know we want to use the receiving end in the thread that -the workers spawn, so we’re going to reference the `receiver` parameter in the -closure. The code shown here in Listing 20-17 won’t quite compile yet: +pool creates the channel. We know we want to use the receiving end in the +thread that the workers spawn, so we’ll reference the `receiver` parameter in +the closure. The code in Listing 20-17 won’t quite compile yet. Filename: src/lib.rs @@ -814,10 +768,10 @@ impl Worker { Listing 20-17: Passing the receiving end of the channel to the workers -These are small and straightforward changes: we pass the receiving end of the -channel into `Worker::new`, and then we use it inside of the closure. +We’ve made some small and straightforward changes: we pass the receiving end of +the channel into `Worker::new`, and then we use it inside the closure. -If we try to check this, we get this error: +When we try to check this code, we get this error: ```text $ cargo check @@ -834,26 +788,21 @@ error[E0382]: use of moved value: `receiver` ``` The code is trying to pass `receiver` to multiple `Worker` instances. This -won’t work, as we recall from Chapter 16: the channel implementation provided -by Rust is multiple *producer*, single *consumer*. This means we can’t just -clone the consuming end of the channel to fix this. Even if we could, that’s -not the technique we’d want to use; we want to distribute the jobs across -threads by sharing the single `receiver` between all of the workers. - - - +won’t work, as you’ll recall from Chapter 16: the channel implementation that +Rust provides is multiple *producer*, single *consumer*. This means we can’t +just clone the consuming end of the channel to fix this code. Even if we could, +that is not the technique we would want to use; instead, we want to distribute +the jobs across threads by sharing the single `receiver` among all the workers. Additionally, taking a job off the channel queue involves mutating the -`receiver`, so the threads need a safe way to share and modify `receiver`, -otherwise we might get race conditions (as covered in Chapter 16). +`receiver`, so the threads need a safe way to share and modify `receiver`; +otherwise, we might get race conditions (as covered in Chapter 16). -Remembering the thread-safe smart pointers that we discussed in Chapter 16, in -order to share ownership across multiple threads and allow the threads to -mutate the value, we need to use `Arc>`. `Arc` will let multiple -workers own the receiver, and `Mutex` will make sure that only one worker is -getting a job from the receiver at a time. Listing 20-18 shows the changes we -need to make: +Recall the thread-safe smart pointers discussed in Chapter 16: to share +ownership across multiple threads and allow the threads to mutate the value, we +need to use `Arc>`. The `Arc` type will let multiple workers own the +receiver, and `Mutex` will ensure that only one worker gets a job from the +receiver at a time. Listing 20-18 shows the changes we need to make. Filename: src/lib.rs @@ -862,7 +811,6 @@ need to make: # use std::sync::mpsc; use std::sync::Arc; use std::sync::Mutex; - // --snip-- # pub struct ThreadPool { @@ -916,7 +864,7 @@ impl Worker { ``` Listing 20-18: Sharing the receiving end of the channel -between the workers using `Arc` and `Mutex` +among the workers using `Arc` and `Mutex` In `ThreadPool::new`, we put the receiving end of the channel in an `Arc` and a `Mutex`. For each new worker, we clone the `Arc` to bump the reference count so @@ -926,11 +874,11 @@ With these changes, the code compiles! We’re getting there! #### Implementing the `execute` Method -Let’s finally implement the `execute` method on `ThreadPool`. We’re also going -to change `Job` from a struct to a type alias for a trait object that holds the -type of closure that `execute` receives. As we discussed in the “Type Aliases -Create Type Synonyms” section of Chapter 19, type aliases allow us to make long -types shorter. Take a look at Listing 20-19: +Let’s finally implement the `execute` method on `ThreadPool`. We’ll also change +`Job` from a struct to a type alias for a trait object that holds the type of +closure that `execute` receives. As discussed in the “Creating Type Synonyms +with Type Aliases” section of Chapter 19, type aliases allow us to make long +types shorter. Look at Listing 20-19. Filename: src/lib.rs @@ -943,7 +891,7 @@ types shorter. Take a look at Listing 20-19: # use std::sync::mpsc; # struct Worker {} -type Job = Box; +type Job = Box; impl ThreadPool { // --snip-- @@ -962,22 +910,22 @@ impl ThreadPool { ``` Listing 20-19: Creating a `Job` type alias for a `Box` -that holds each closure, then sending the job down the channel +that holds each closure and then sending the job down the channel After creating a new `Job` instance using the closure we get in `execute`, we send that job down the sending end of the channel. We’re calling `unwrap` on -`send` for the case that sending fails, which might happen if, for example, we -stop all of our threads from executing, meaning the receiving end has stopped -receiving new messages. At the moment, though, we can’t stop our threads -executing; our threads continue executing as long as the pool exists. The -reason we use `unwrap`, then, is that we we know the failure case won’t happen -but the compiler can’t tell that. +`send` for the case that sending fails. This might happen if, for example, we +stop all our threads from executing, meaning the receiving end has stopped +receiving new messages. At the moment, we can’t stop our threads from +executing: our threads continue executing as long as the pool exists. The +reason we use `unwrap` is that we know the failure case won’t happen, but the +compiler doesn’t know that. But we’re not quite done yet! In the worker, our closure being passed to `thread::spawn` still only *references* the receiving end of the channel. Instead, we need the closure to loop forever, asking the receiving end of the -channel for a job, and running the job when it gets one. Let’s make the change -shown in Listing 20-20 to `Worker::new`: +channel for a job and running the job when it gets one. Let’s make the change +shown in Listing 20-20 to `Worker::new`. Filename: src/lib.rs @@ -1007,21 +955,21 @@ impl Worker { Listing 20-20: Receiving and executing the jobs in the worker’s thread -Here, we first call `lock` on the `receiver` to acquire the mutex, then -`unwrap` to panic on any errors. Acquiring a lock might fail if the mutex is in -a *poisoned* state, which can happen if some other thread panicked while -holding the lock, rather than releasing the lock. In this situation, calling +Here, we first call `lock` on the `receiver` to acquire the mutex, and then we +call `unwrap` to panic on any errors. Acquiring a lock might fail if the mutex +is in a *poisoned* state, which can happen if some other thread panicked while +holding the lock rather than releasing the lock. In this situation, calling `unwrap` to have this thread panic is the correct action to take. Feel free to change this `unwrap` to an `expect` with an error message that is meaningful to -you if you’d like. +you. -If we get the lock on the mutex, then we call `recv` to receive a `Job` from -the channel. A final `unwrap` moves past any errors here as well, which might -occur if the thread holding the sending side of the channel has shut down, -similar to how the `send` method returns `Err` if the receiving side shuts down. +If we get the lock on the mutex, we call `recv` to receive a `Job` from the +channel. A final `unwrap` moves past any errors here as well, which might occur +if the thread holding the sending side of the channel has shut down, similar to +how the `send` method returns `Err` if the receiving side shuts down. -The call to `recv` *blocks*, so if there’s no job yet, the current thread will -sit until a job becomes available. The `Mutex` makes sure that only one +The call to `recv` blocks, so if there is no job yet, the current thread will +wait until a job becomes available. The `Mutex` ensures that only one `Worker` thread at a time is trying to request a job. Theoretically, this code should compile. Unfortunately, the Rust compiler isn’t @@ -1037,52 +985,51 @@ statically determined | ^^^^^^ ``` -This error is fairly cryptic, and that’s because the problem is fairly cryptic. -In order to call a `FnOnce` closure that is stored in a `Box` (which is what -our `Job` type alias is), the closure needs to be able to move itself *out* of -the `Box` because the closure takes ownership of `self` when we call it. In -general, Rust doesn’t allow us to move value out of a `Box` because Rust -doesn’t know how big the value inside the `Box` is going to be; recall in -Chapter 15 that we used `Box` precisely because we had something of an -unknown size that we wanted to store in a `Box` to get a value of a known -size. +This error is fairly cryptic because the problem is fairly cryptic. To call a +`FnOnce` closure that is stored in a `Box` (which is what our `Job` type +alias is), the closure needs to move itself *out* of the `Box` because the +closure takes ownership of `self` when we call it. In general, Rust doesn’t +allow us to move a value out of a `Box` because Rust doesn’t know how big +the value inside the `Box` will be: recall in Chapter 15 that we used +`Box` precisely because we had something of an unknown size that we wanted +to store in a `Box` to get a value of a known size. -We saw in Chapter 17, Listing 17-15 that we can write methods that use the -syntax `self: Box`, which allows the method to take ownership of a `Self` -value stored in a `Box`. That’s exactly what we want to do here, but -unfortunately Rust won’t let us: the part of Rust that implements behavior when -a closure is called isn’t implemented using `self: Box`. So Rust doesn’t -yet understand that it could use `self: Box` in this situation in order -to take ownership of the closure and move the closure out of the `Box`. +As you saw in Listing 17-15, we can write methods that use the syntax `self: +Box`, which allows the method to take ownership of a `Self` value stored +in a `Box`. That’s exactly what we want to do here, but unfortunately Rust +won’t let us: the part of Rust that implements behavior when a closure is +called isn’t implemented using `self: Box`. So Rust doesn’t yet +understand that it could use `self: Box` in this situation to take +ownership of the closure and move the closure out of the `Box`. -Rust is still a work in progress with places that the compiler could be +Rust is still a work in progress with places where the compiler could be improved, but in the future, the code in Listing 20-20 should work just fine. -There are people just like you working to fix this and other issues! Once -you’ve finished the book, we would love for you to join in. +People just like you are working to fix this and other issues! After you’ve +finished this book, we would love for you to join in. -But for now, let’s work around this problem with a handy trick. We can tell +But for now, let’s work around this problem using a handy trick. We can tell Rust explicitly that in this case we can take ownership of the value inside the -`Box` using `self: Box`, and once we have ownership of the closure, we -can call it. This involves defining a new trait `FnBox` with the method -`call_box` that will use `self: Box` in its signature, defining `FnBox` +`Box` using `self: Box`; then, once we have ownership of the closure, +we can call it. This involves defining a new trait `FnBox` with the method +`call_box` that will use `self: Box` in its signature, defining `FnBox` for any type that implements `FnOnce()`, changing our type alias to use the new trait, and changing `Worker` to use the `call_box` method. These changes are -shown in Listing 20-21: +shown in Listing 20-21. Filename: src/lib.rs ```rust,ignore trait FnBox { - fn call_box(self: Box); + fn call_box(self: Box); } impl FnBox for F { - fn call_box(self: Box) { + fn call_box(self: Box) { (*self)() } } -type Job = Box; +type Job = Box; // --snip-- @@ -1107,12 +1054,12 @@ impl Worker { ``` Listing 20-21: Adding a new trait `FnBox` to work around -the current limitations of `Box` +the current limitations of `Box` First, we create a new trait named `FnBox`. This trait has the one method `call_box`, which is similar to the `call` methods on the other `Fn*` traits -except that it takes `self: Box` in order to take ownership of `self` and -move the value out of the `Box`. +except that it takes `self: Box` to take ownership of `self` and move the +value out of the `Box`. Next, we implement the `FnBox` trait for any type `F` that implements the `FnOnce()` trait. Effectively, this means that any `FnOnce()` closures can use @@ -1121,19 +1068,16 @@ move the closure out of the `Box` and call the closure. We now need our `Job` type alias to be a `Box` of anything that implements our new trait `FnBox`. This will allow us to use `call_box` in `Worker` when we get -a `Job` value. Implementing the `FnBox` trait for any `FnOnce()` closure means -we don’t have to change anything about the actual values we’re sending down the -channel. +a `Job` value instead of invoking the closure directly. Implementing the +`FnBox` trait for any `FnOnce()` closure means we don’t have to change anything +about the actual values we’re sending down the channel. Now Rust is able to +recognize that what we want to do is fine. -Finally, in the closure run in the thread in `Worker::new`, we use `call_box` -instead of invoking the closure directly. Now Rust is able to understand that -what we want to do is fine. +This trick is very sneaky and complicated. Don’t worry if it doesn’t make +perfect sense; someday, it will be completely unnecessary. -This is a very sneaky, complicated trick. Don’t worry too much if it doesn’t -make perfect sense; someday, it will be completely unnecessary. - -With this trick, our thread pool is in a working state! Give it a `cargo run`, -and make some requests: +With the implementation of this trick, our thread pool is in a working state! +Give it a `cargo run` and make some requests: ```text $ cargo run @@ -1164,7 +1108,7 @@ warning: field is never used: `thread` Finished dev [unoptimized + debuginfo] target(s) in 0.99 secs Running `target/debug/hello` - Worker 0 got a job; executing. +Worker 0 got a job; executing. Worker 2 got a job; executing. Worker 1 got a job; executing. Worker 3 got a job; executing. @@ -1176,13 +1120,14 @@ Worker 0 got a job; executing. Worker 2 got a job; executing. ``` -Success! We now have a thread pool executing connections asynchronously. There -are never more than four threads created, so our system won’t get overloaded if -the server receives a lot of requests. If we make a request to `/sleep`, the -server will be able to serve other requests by having another thread run them. +Success! We now have a thread pool that executes connections asynchronously. +There are never more than four threads created, so our system won’t get +overloaded if the server receives a lot of requests. If we make a request to +*/sleep*, the server will be able to serve other requests by having another +thread run them. -After learning about the `while let` loop in Chapter 18, you might be -wondering why we didn’t write the worker thread like this: +After learning about the `while let` loop in Chapter 18, you might be wondering +why we didn’t write the worker thread code as shown in Listing 20-22. Filename: src/lib.rs @@ -1210,18 +1155,18 @@ impl Worker { Listing 20-22: An alternative implementation of `Worker::new` using `while let` -This code compiles and runs, but doesn’t result in the desired threading +This code compiles and runs but doesn’t result in the desired threading behavior: a slow request will still cause other requests to wait to be -processed. The reason why is somewhat subtle: the `Mutex` struct has no public +processed. The reason is somewhat subtle: the `Mutex` struct has no public `unlock` method because the ownership of the lock is based on the lifetime of the `MutexGuard` within the `LockResult>` that the `lock` -method returns. This allows the borrow checker to enforce at compile time that -we never access a resource guarded by a `Mutex` without holding the lock, but -it can also result in holding the lock longer than intended if we don’t think -carefully about the lifetime of the `MutexGuard`. Because the values in the -the `while` expression remain in scope for the duration of the block, the lock -remains held for the duration of the call to `job.call_box()`, meaning other -workers cannot receive jobs. +method returns. At compile time, the borrow checker can then enforce the rule +that a resource guarded by a `Mutex` cannot be accessed unless we hold the +lock. But this implementation can also result in the lock being held longer +than intended if we don’t think carefully about the lifetime of the +`MutexGuard`. Because the values in the `while` expression remain in scope +for the duration of the block, the lock remains held for the duration of the +call to `job.call_box()`, meaning other workers cannot receive jobs. By using `loop` instead and acquiring the lock and a job within the block rather than outside it, the `MutexGuard` returned from the `lock` method is diff --git a/src/doc/book/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md b/src/doc/book/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md index 0c60b00e25..f333c6d94c 100644 --- a/src/doc/book/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md +++ b/src/doc/book/2018-edition/src/ch20-03-graceful-shutdown-and-cleanup.md @@ -3,24 +3,23 @@ The code in Listing 20-21 is responding to requests asynchronously through the use of a thread pool, as we intended. We get some warnings about the `workers`, `id`, and `thread` fields that we’re not using in a direct way that reminds us -we’re not cleaning anything up. When we use the less elegant ctrl-C method to halt the main thread, all other +we’re not cleaning up anything. When we use the less elegant ctrl-c method to halt the main thread, all other threads are stopped immediately as well, even if they’re in the middle of serving a request. -We’re now going to implement the `Drop` trait to call `join` on each of the -threads in the pool so they can finish the requests they’re working on before -closing. Then we’ll implement a way to tell the threads they should stop -accepting new requests and shut down. To see this code in action, we’ll modify -our server to only accept two requests before gracefully shutting down its -thread pool. +Now we’ll implement the `Drop` trait to call `join` on each of the threads in +the pool so they can finish the requests they’re working on before closing. +Then we’ll implement a way to tell the threads they should stop accepting new +requests and shut down. To see this code in action, we’ll modify our server to +accept only two requests before gracefully shutting down its thread pool. ### Implementing the `Drop` Trait on `ThreadPool` -Let’s start with implementing `Drop` for our thread pool. When the pool is -dropped, our threads should all join on to make sure they finish their work. +Let’s start with implementing `Drop` on our thread pool. When the pool is +dropped, our threads should all join to make sure they finish their work. Listing 20-23 shows a first attempt at a `Drop` implementation; this code won’t -quite work yet: +quite work yet. Filename: src/lib.rs @@ -39,14 +38,14 @@ impl Drop for ThreadPool { Listing 20-23: Joining each thread when the thread pool goes out of scope -First we loop through each of the thread pool `workers`. We use `&mut` for this -because `self` is itself a mutable reference and we also need to be able to +First, we loop through each of the thread pool `workers`. We use `&mut` for +this because `self` is a mutable reference, and we also need to be able to mutate `worker`. For each worker, we print a message saying that this particular worker is shutting down, and then we call `join` on that worker’s thread. If the call to `join` fails, we use `unwrap` to make Rust panic and go into an ungraceful shutdown. -Here’s the error we get if we compile this code: +Here is the error we get when we compile this code: ```text error[E0507]: cannot move out of borrowed content @@ -56,16 +55,16 @@ error[E0507]: cannot move out of borrowed content | ^^^^^^ cannot move out of borrowed content ``` -This tells use we can’t call `join` because we only have a mutable borrow of -each `worker`, and `join` takes ownership of its argument. In order to solve -this, we need a way to move the thread out of the `Worker` instance that owns -`thread` so that `join` can consume the thread. We saw a way to do this in -Listing 17-15: if `Worker` holds an `Option` instead, we -can call the `take` method on the `Option` to move the value out of the `Some` -variant and leave a `None` variant in its place. In other words, a `Worker` -that is running will have a `Some` variant in `thread`, and when we want to -clean up a worker, we’ll replace `Some` with `None` so the worker doesn’t have -a thread to run. +The error tells us we can’t call `join` because we only have a mutable borrow +of each `worker` and `join` takes ownership of its argument. To solve this +issue, we need to move the thread out of the `Worker` instance that owns +`thread` so `join` can consume the thread. We did this in Listing 17-15: if +`Worker` holds an `Option` instead, we can call the +`take` method on the `Option` to move the value out of the `Some` variant and +leave a `None` variant in its place. In other words, a `Worker` that is running +will have a `Some` variant in `thread`, and when we want to clean up a +`Worker`, we’ll replace `Some` with `None` so the `Worker` doesn’t have a +thread to run. So we know we want to update the definition of `Worker` like this: @@ -106,7 +105,7 @@ error[E0308]: mismatched types Let’s address the second error, which points to the code at the end of `Worker::new`; we need to wrap the `thread` value in `Some` when we create a -new `Worker`. Make the following changes to fix this: +new `Worker`. Make the following changes to fix this error: Filename: src/lib.rs @@ -143,25 +142,26 @@ impl Drop for ThreadPool { } ``` -As we saw in Chapter 17, the `take` method on `Option` takes the `Some` variant -out and leaves `None` in its place. We’re using `if let` to destructure the -`Some` and get the thread, then we call `join` on the thread. If a worker’s +As discussed in Chapter 17, the `take` method on `Option` takes the `Some` +variant out and leaves `None` in its place. We’re using `if let` to destructure +the `Some` and get the thread; then we call `join` on the thread. If a worker’s thread is already `None`, we know that worker has already had its thread cleaned up, so nothing happens in that case. ### Signaling to the Threads to Stop Listening for Jobs -With this, our code compiles without any warnings. Bad news though, this code -doesn’t function the way we want it to yet. The key is the logic in the -closures run by the threads of the `Worker` instances: at the moment we call -`join`, but that won’t shut down the threads because they `loop` forever looking -for jobs. If we try to drop our `ThreadPool` with this implementation, the main -thread will block forever waiting for the first thread to finish. +With all the changes we’ve made, our code compiles without any warnings. But +the bad news is this code doesn’t function the way we want it to yet. The key +is the logic in the closures run by the threads of the `Worker` instances: at +the moment, we call `join`, but that won’t shut down the threads because they +`loop` forever looking for jobs. If we try to drop our `ThreadPool` with our +current implementation of `drop`, the main thread will block forever waiting +for the first thread to finish. -To fix this, we’re going to modify the threads so they listen for either a -`Job` to run or a signal that they should stop listening and exit the infinite -loop. Instead of `Job` instances, then, our channel will send one of these two -enum variants: +To fix this problem, we’ll modify the threads so they listen for either a `Job` +to run or a signal that they should stop listening and exit the infinite loop. +Instead of `Job` instances, our channel will send one of these two enum +variants. Filename: src/lib.rs @@ -178,7 +178,7 @@ thread should run, or it will be a `Terminate` variant that will cause the thread to exit its loop and stop. We need to adjust the channel to use values of type `Message` rather than type -`Job`, as shown in Listing 20-24: +`Job`, as shown in Listing 20-24. Filename: src/lib.rs @@ -239,7 +239,7 @@ impl Worker { Listing 20-24: Sending and receiving `Message` values and exiting the loop if a `Worker` receives `Message::Terminate` -To incorporate the `Message` enum we need to change `Job` to `Message` in two +To incorporate the `Message` enum, we need to change `Job` to `Message` in two places: the definition of `ThreadPool` and the signature of `Worker::new`. The `execute` method of `ThreadPool` needs to send jobs wrapped in the `Message::NewJob` variant. Then, in `Worker::new` where a `Message` is received @@ -248,9 +248,9 @@ received, and the thread will break out of the loop if the `Terminate` variant is received. With these changes, the code will compile and continue to function in the same -way as it has been. We will get a warning, though, because we aren’t creating -any messages of the `Terminate` variety. Let’s fix this by changing our `Drop` -implementation to look like Listing 20-25: +way as it did after Listing 20-21. But we’ll get a warning because we aren’t +creating any messages of the `Terminate` variety. Let’s fix this warning by +changing our `Drop` implementation to look like Listing 20-25. Filename: src/lib.rs @@ -279,8 +279,8 @@ impl Drop for ThreadPool { Listing 20-25: Sending `Message::Terminate` to the workers before calling `join` on each worker thread -We’re now iterating over the workers twice, once to send one `Terminate` -message for each worker, and once to call `join` on each worker’s thread. If we +We’re now iterating over the workers twice: once to send one `Terminate` +message for each worker and once to call `join` on each worker’s thread. If we tried to send a message and `join` immediately in the same loop, we couldn’t guarantee that the worker in the current iteration would be the one to get the message from the channel. @@ -290,19 +290,19 @@ two workers. If we used a single loop to iterate through each worker, on the first iteration a terminate message would be sent down the channel and `join` called on the first worker’s thread. If that first worker was busy processing a request at that moment, the second worker would pick up the terminate message -from the channel and shut down. We’d be left waiting on the first worker to -shut down, but it never will because the second thread picked up the terminate +from the channel and shut down. We would be left waiting on the first worker to +shut down, but it never would because the second thread picked up the terminate message. Deadlock! -To prevent this, we first put all of our `Terminate` messages on the channel in -one loop, and then we join on all the threads in another loop. Each worker will -stop receiving requests on the channel once it gets a terminate message, -meaning we can be sure that if we send the same number of terminate messages as -there are workers, each worker will receive a terminate message before `join` -is called on its thread. +To prevent this scenario, we first put all of our `Terminate` messages on the +channel in one loop; then we join on all the threads in another loop. Each +worker will stop receiving requests on the channel once it gets a terminate +message. So, we can be sure that if we send the same number of terminate +messages as there are workers, each worker will receive a terminate message +before `join` is called on its thread. -In order to see this code in action, let’s modify `main` to only accept two -requests before gracefully shutting the server down as shown in Listing 20-26: +To see this code in action, let’s modify `main` to accept only two requests +before gracefully shutting down the server, as shown in Listing 20-26. Filename: src/bin/main.rs @@ -327,16 +327,15 @@ fn main() { requests by exiting the loop You wouldn’t want a real-world web server to shut down after serving only two -requests, this just demonstrates the graceful shutdown and cleanup in working -order. +requests. This code just demonstrates that the graceful shutdown and cleanup is +in working order. -The `take` method is defined in the `Iterator` trait, and limits the iteration -to the first 2 items at most. The `ThreadPool` will go out of scope at the end -of `main`, and we’ll see the `drop` implementation run. +The `take` method is defined in the `Iterator` trait and limits the iteration +to the first two items at most. The `ThreadPool` will go out of scope at the +end of `main`, and the `drop` implementation will run. Start the server with `cargo run`, and make three requests. The third request -should error, and in your terminal you should see output that looks similar to -this: +should error, and in your terminal you should see output similar to this: ```text $ cargo run @@ -358,26 +357,27 @@ Shutting down worker 2 Shutting down worker 3 ``` -You may see a different ordering of workers and messages printed. We can see -how this works from the messages: workers zero and three got the first two -requests, and then on the third request the server stopped accepting +You might see a different ordering of workers and messages printed. We can see +how this code works from the messages: workers 0 and 3 got the first two +requests, and then on the third request, the server stopped accepting connections. When the `ThreadPool` goes out of scope at the end of `main`, its `Drop` implementation kicks in, and the pool tells all workers to terminate. The workers each print a message when they see the terminate message, and then the thread pool calls `join` to shut down each worker thread. -One interesting aspect of this particular execution: notice that the -`ThreadPool` sent the terminate messages down the channel, and before any -worker received the messages, we tried to join worker 0. Worker 0 had not yet -gotten the terminate message, so the main thread blocked waiting for worker 0 -to finish. In the meantime, each of the workers received the termination -messages. Once worker 0 finished, the main thread waited for the rest of the -workers to finish, and they had all received the termination message and were -able to shut down at that point. +Notice one interesting aspect of this particular execution: the `ThreadPool` +sent the terminate messages down the channel, and before any worker received +the messages, we tried to join worker 0. Worker 0 had not yet received the +terminate message, so the main thread blocked waiting for worker 0 to finish. +In the meantime, each of the workers received the termination messages. When +worker 0 finished, the main thread waited for the rest of the workers to +finish. At that point, they had all received the termination message and were +able to shut down. + +Congrats! We’ve now completed our project; we have a basic web server that uses +a thread pool to respond asynchronously. We’re able to perform a graceful +shutdown of the server, which cleans up all the threads in the pool. -Congrats! We have now completed our project, and we have a basic web server -that uses a thread pool to respond asynchronously. We’re able to perform a -graceful shutdown of the server, which cleans up all the threads in the pool. Here’s the full code for reference: Filename: src/bin/main.rs @@ -389,7 +389,7 @@ use hello::ThreadPool; use std::io::prelude::*; use std::net::TcpListener; use std::net::TcpStream; -use std::fs::File; +use std::fs; use std::thread; use std::time::Duration; @@ -424,10 +424,7 @@ fn handle_connection(mut stream: TcpStream) { ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html") }; - let mut file = File::open(filename).unwrap(); - let mut contents = String::new(); - - file.read_to_string(&mut contents).unwrap(); + let contents = fs::read_to_string(filename).unwrap(); let response = format!("{}{}", status_line, contents); @@ -464,7 +461,7 @@ impl FnBox for F { } } -type Job = Box; +type Job = Box; impl ThreadPool { /// Create a new ThreadPool. @@ -559,21 +556,21 @@ impl Worker { } ``` -There’s more we could do here! If you’d like to continue enhancing this -project, here are some ideas: +We could do more here! If you want to continue enhancing this project, here are +some ideas: -- Add more documentation to `ThreadPool` and its public methods -- Add tests of the library’s functionality -- Change calls to `unwrap` to more robust error handling -- Use `ThreadPool` to perform some task other than serving web requests -- Find a thread pool crate on crates.io and implement a similar web server - using the crate instead and compare its API and robustness to the thread pool - we implemented +* Add more documentation to `ThreadPool` and its public methods. +* Add tests of the library’s functionality. +* Change calls to `unwrap` to more robust error handling. +* Use `ThreadPool` to perform some task other than serving web requests. +* Find a thread pool crate on *https://crates.io/* and implement a similar web + server using the crate instead. Then compare its API and robustness to the + thread pool we implemented. ## Summary -Well done! You’ve made it to the end of the book! We’d like to thank you for -joining us on this tour of Rust. You’re now ready to go out and implement your -own Rust projects and help with other people’s. Remember there’s a community of -other Rustaceans who would love to help you with any challenges you encounter -on your Rust journey. +Well done! You’ve made it to the end of the book! We want to thank you for +joining us on this tour of Rust. You’re now ready to implement your own Rust +projects and help with other peoples’ projects. Keep in mind that there is a +welcoming community of other Rustaceans who would love to help you with any +challenges you encounter on your Rust journey. diff --git a/src/doc/book/CONTRIBUTING.md b/src/doc/book/CONTRIBUTING.md index a4c64127e2..324dff6fc9 100644 --- a/src/doc/book/CONTRIBUTING.md +++ b/src/doc/book/CONTRIBUTING.md @@ -37,12 +37,11 @@ We'd especially love help translating the second edition of the book! See the [Translations] label to join in efforts that are currently in progress. Open a new issue to start working on a new language! We're waiting on [mdbook support] for multiple languages before we merge any in, but feel free to -start! The chapters in [the frozen column] of the project won't see major -changes, so if you start with those, you won't have to redo work :) +start! The second edition is frozen and won't see major changes, so if +you start with that, you won't have to redo work :) [Translations]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations [mdbook support]: https://github.com/azerupi/mdBook/issues/5 -[the frozen column]: https://github.com/rust-lang/book/projects/1 ## Edition specific details @@ -60,19 +59,9 @@ that we ultimately wouldn't accept. ## Contributing to the Second Edition -We're currently working with No Starch Press to bring the second edition of -the book to print. Each chapter goes through [a number of stages][project]. -At this This means we're not able to make large changes to chapters that are -in any column to the right of, and including, the "Frozen" column on that -board. - -[project]: https://github.com/rust-lang/book/projects/1 - -We *may* still able to make very small corrections that pertain to -correctness issues. If you find something, don't hesitate to open a pull -request, but we may not be able to accept it. You might want to check -in the 2018 edition to see if the corresponding error is still there, -and make the fix against that as well. +The second edition is completely frozen, and not accepting changes. It's +meant to be in sync with the print version available from No Starch +Press. ## Contributing to the First Edition diff --git a/src/doc/book/README.md b/src/doc/book/README.md index 2563c6ceed..58e7502390 100644 --- a/src/doc/book/README.md +++ b/src/doc/book/README.md @@ -6,7 +6,7 @@ This repository contains the source of all editions of "the Rust Programming Language". The second edition will also be available in dead-tree form by No Starch -Press, available around May 2018. Check [the No Starch Page][nostarch] for +Press, available around June 2018. Check [the No Starch Page][nostarch] for the latest information on the release date and how to order. [nostarch]: https://nostarch.com/rust @@ -34,7 +34,7 @@ $ cargo install mdbook --vers [version-num] ## Building -To build the book, first `cd` into one of the directory of the edition of the +To build the book, first `cd` into the directory of the edition of the book you'd like to build. For example, the `first-edition` or `second-edition` directory. Then type: @@ -72,9 +72,15 @@ $ mdbook test We'd love your help! Please see [CONTRIBUTING.md][contrib] to learn about the kinds of contributions we're looking for. +### 2018 Edition + +The "2018" Edition is in the process of being updated with the language changes +that will be available with the 2018 Edition of the Rust language. All new +contributions should be to this edition. + ### Second Edition -The second edition of The Rust Programming Language is getting ever closer to being printed! +The second edition is frozen, and is not accepting any changes at this time. ### First Edition @@ -85,16 +91,15 @@ The first edition is frozen, and is not accepting any changes at this time. ### Translations -We'd especially love help translating the second edition of the book! See the +We'd especially love help translating the second edition or 2018 edition of the book! See the [Translations] label to join in efforts that are currently in progress. Open a new issue to start working on a new language! We're waiting on [mdbook support] for multiple languages before we merge any in, but feel free to -start! The chapters in [the frozen column] of the project won't see major -changes, so if you start with those, you won't have to redo work :) +start! The second edition is frozen and won't see major +changes, so if you start with that, you won't have to redo work :) [Translations]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations [mdbook support]: https://github.com/azerupi/mdBook/issues/5 -[the frozen column]: https://github.com/rust-lang/book/projects/1 ## No Starch @@ -136,4 +141,4 @@ To scan source files for spelling errors, you can use the `spellcheck.sh` script. It needs a dictionary of valid words, which is provided in `dictionary.txt`. If the script produces a false positive (say, you used word `BTreeMap` which the script considers invalid), you need to add this word to -`dictionary.txt` (keep the sorted order for consistency). \ No newline at end of file +`dictionary.txt` (keep the sorted order for consistency). diff --git a/src/doc/book/ci/build.sh b/src/doc/book/ci/build.sh index 00901e3b3b..e096b86bdd 100644 --- a/src/doc/book/ci/build.sh +++ b/src/doc/book/ci/build.sh @@ -33,7 +33,7 @@ cd .. # tests for the second edition cd second-edition echo 'Spellchecking second edition...' -bash spellcheck.sh list +bash ../ci/spellcheck.sh list echo 'Testing second edition...' mdbook test echo 'Building second edition...' @@ -46,7 +46,7 @@ cd .. # tests for the 2018 edition cd 2018-edition echo 'Spellchecking 2018 edition...' -bash spellcheck.sh list +bash ../ci/spellcheck.sh list echo 'Testing 2018 edition...' mdbook test echo 'Building 2018 edition...' diff --git a/src/doc/book/second-edition/dictionary.txt b/src/doc/book/ci/dictionary.txt similarity index 100% rename from src/doc/book/second-edition/dictionary.txt rename to src/doc/book/ci/dictionary.txt diff --git a/src/doc/book/2018-edition/spellcheck.sh b/src/doc/book/ci/spellcheck.sh similarity index 100% rename from src/doc/book/2018-edition/spellcheck.sh rename to src/doc/book/ci/spellcheck.sh diff --git a/src/doc/book/index.md b/src/doc/book/index.md index 66330755dc..661e9fb667 100644 --- a/src/doc/book/index.md +++ b/src/doc/book/index.md @@ -6,19 +6,25 @@ multiple editions. The source for all editions lives [on GitHub](https://github.com/rust-lang/book). Please open issues with any questions, concerns, or tweaks. -If you're not sure what edition you want to read, Go with the [second -edition](second-edition/index.html), as it's the most polished. +## 2018 Edition + +The 2018 edition of the book is a "living version" of the book; based on the +second edition, it will be updated as Rust updates. If you're not sure what +version of the book to read, you should prefer this version. + +You can find the 2018 edition [here](2018-edition/index.html). ## Second Edition -The second edition is still receiving some minor edits, but is effectively -complete. It will be [available in dead-tree form through NoStarch -Press](https://nostarch.com/Rust) once these final edits are complete. +The second edition is a complete re-write of TRPL, from the ground up, and is +therefore very different from the first edition. It's also based on Rust 1.21, +and so may be missing features that landed in stable after that release. -The second edition is a complete re-write of TRPL, from the ground up, -and is therefore very different from the first edition. It's also based -on Rust 1.21, and so may be missing features that landed in stable after -that release. +You can purchase a [dead-tree copy from NoStarch +Press](https://nostarch.com/Rust). + +This edition of the book is frozen; it contains exactly what's in the printed +book. You can find the second edition [here](second-edition/index.html). @@ -27,4 +33,4 @@ You can find the second edition [here](second-edition/index.html). The first edition is completely frozen, but is still included in the documentation for historical reasons. -You can find the first edition [here](first-edition/index.html). \ No newline at end of file +You can find the first edition [here](first-edition/index.html). diff --git a/src/doc/book/redirects/associated-types.md b/src/doc/book/redirects/associated-types.md index 4083f93986..bc30e44368 100644 --- a/src/doc/book/redirects/associated-types.md +++ b/src/doc/book/redirects/associated-types.md @@ -20,4 +20,4 @@ Here are the relevant sections in the new and old books: [1]: first-edition/associated-types.html -[2]: second-edition/ch19-03-advanced-traits.html#associated-types-specify-placeholder-types-in-trait-definitions +[2]: second-edition/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types diff --git a/src/doc/book/redirects/type-aliases.md b/src/doc/book/redirects/type-aliases.md index 33e9f1faf7..f7703a242b 100644 --- a/src/doc/book/redirects/type-aliases.md +++ b/src/doc/book/redirects/type-aliases.md @@ -17,5 +17,5 @@ Here are the relevant sections in the new and old books: [1]: first-edition/type-aliases.html -[2]: second-edition/ch19-04-advanced-types.html#type-aliases-create-type-synonyms +[2]: second-edition/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases diff --git a/src/doc/book/redirects/unsized-types.md b/src/doc/book/redirects/unsized-types.md index 0f7080f118..9530b3ef83 100644 --- a/src/doc/book/redirects/unsized-types.md +++ b/src/doc/book/redirects/unsized-types.md @@ -21,4 +21,4 @@ Here are the relevant sections in the new and old books: [1]: first-edition/unsized-types.html -[2]: second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-sized +[2]: second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait diff --git a/src/doc/book/second-edition/nostarch/chapter16.md b/src/doc/book/second-edition/nostarch/chapter16.md index 530ce57a49..b614d11e9c 100644 --- a/src/doc/book/second-edition/nostarch/chapter16.md +++ b/src/doc/book/second-edition/nostarch/chapter16.md @@ -28,7 +28,7 @@ subtle bugs and is easy to refactor without introducing new bugs. > Note: For simplicity’s sake, we’ll refer to many of the problems as > concurrent rather than being more precise by saying concurrent and/or > parallel. If this book was specifically about concurrency and/or parallelism, -> we’d be more. specific. For this chapter, please mentally substitute +> we’d be more specific. For this chapter, please mentally substitute > concurrent and/or parallel whenever we use concurrent. Many languages are dogmatic about the solutions they offer for handling diff --git a/src/doc/book/second-edition/spellcheck.sh b/src/doc/book/second-edition/spellcheck.sh deleted file mode 100755 index fd3aa04e1d..0000000000 --- a/src/doc/book/second-edition/spellcheck.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash -# 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 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -aspell --version - -# Checks project markdown files for spell errors - -# Notes: - -# This script needs dictionary file ($dict_filename) with project-specific -# valid words. If this file is missing, first invocation of a script generates -# a file of words considered typos at the moment. User should remove real typos -# from this file and leave only valid words. When script generates false -# positive after source modification, new valid word should be added -# to dictionary file. - -# Default mode of this script is interactive. Each source file is scanned for -# typos. aspell opens window, suggesting fixes for each found typo. Original -# files with errors will be backed up to files with format "filename.md.bak". - -# When running in CI, this script should be run in "list" mode (pass "list" -# as first argument). In this mode script scans all files and reports found -# errors. Exit code in this case depends on scan result: -# 1 if any errors found, -# 0 if all is clear. - -# Script skips words with length less than or equal to 3. This helps to avoid -# some false positives. - -# We can consider skipping source code in markdown files (```code```) to reduce -# rate of false positives, but then we lose ability to detect typos in code -# comments/strings etc. - -shopt -s nullglob - -dict_filename=./dictionary.txt -markdown_sources=(./src/*.md) -mode="check" - -# aspell repeatedly modifies personal dictionary for some purpose, -# so we should use a copy of our dictionary -dict_path="/tmp/$dict_filename" - -if [[ "$1" == "list" ]]; then - mode="list" -fi - -if [[ ! -f "$dict_filename" ]]; then - # Pre-check mode: generates dictionary of words aspell consider typos. - # After user validates that this file contains only valid words, we can - # look for typos using this dictionary and some default aspell dictionary. - echo "Scanning files to generate dictionary file '$dict_filename'." - echo "Please check that it doesn't contain any misspellings." - - echo "personal_ws-1.1 en 0 utf-8" > "$dict_filename" - cat "${markdown_sources[@]}" | aspell --ignore 3 list | sort -u >> "$dict_filename" -elif [[ "$mode" == "list" ]]; then - # List (default) mode: scan all files, report errors - declare -i retval=0 - - cp "$dict_filename" "$dict_path" - - if [ ! -f $dict_path ]; then - retval=1 - exit "$retval" - fi - - for fname in "${markdown_sources[@]}"; do - command=$(aspell --ignore 3 --personal="$dict_path" "$mode" < "$fname") - if [[ -n "$command" ]]; then - for error in $command; do - # FIXME: Find more correct way to get line number - # (ideally from aspell). Now it can make some false positives, - # because it is just a grep - grep --with-filename --line-number --color=always "$error" "$fname" - done - retval=1 - fi - done - exit "$retval" -elif [[ "$mode" == "check" ]]; then - # Interactive mode: fix typos - cp "$dict_filename" "$dict_path" - - if [ ! -f $dict_path ]; then - retval=1 - exit "$retval" - fi - - for fname in "${markdown_sources[@]}"; do - aspell --ignore 3 --dont-backup --personal="$dict_path" "$mode" "$fname" - done -fi diff --git a/src/doc/book/second-edition/src/appendix-01-keywords.md b/src/doc/book/second-edition/src/appendix-01-keywords.md index e6f48b905c..077b92ba6f 100644 --- a/src/doc/book/second-edition/src/appendix-01-keywords.md +++ b/src/doc/book/second-edition/src/appendix-01-keywords.md @@ -7,6 +7,8 @@ constants, macros, static values, attributes, types, traits, or lifetimes. ### Keywords Currently in Use +The following keywords currently have the functionality described. + * `as` - perform primitive casting, disambiguate the specific trait containing an item, or rename items in `use` and `extern crate` statements * `break` - exit a loop immediately diff --git a/src/doc/book/second-edition/src/appendix-02-operators.md b/src/doc/book/second-edition/src/appendix-02-operators.md index 35e7ed327c..3538c07b1d 100644 --- a/src/doc/book/second-edition/src/appendix-02-operators.md +++ b/src/doc/book/second-edition/src/appendix-02-operators.md @@ -6,189 +6,199 @@ trait bounds, macros, attributes, comments, tuples, and brackets. ### Operators -The following list contains the operators in Rust, an example of how the -operator would appear in context, a short explanation, and whether that -operator is overloadable. If an operator is overloadable, the relevant trait to -use to overload that operator is listed. +Table B-1 contains the operators in Rust, an example of how the operator would +appear in context, a short explanation, and whether that operator is +overloadable. If an operator is overloadable, the relevant trait to use to +overload that operator is listed. +Table B-1: Operators -* `!` (`ident!(...)`, `ident!{...}`, `ident![...]`): denotes macro -expansion. -* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`). -* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`). -* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). -* `%=` (`var %= expr`): arithmetic remainder and assignment. Overloadable -(`RemAssign`). -* `&` (`&expr`, `&mut expr`): borrow. -* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. -* `&` (`expr & expr`): bitwise AND. Overloadable (`BitAnd`). -* `&=` (`var &= expr`): bitwise AND and assignment. Overloadable -(`BitAndAssign`). -* `&&` (`expr && expr`): logical AND. -* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`). -* `*` (`*expr`): dereference. -* `*` (`*const type`, `*mut type`): raw pointer. -* `*=` (`var *= expr`): arithmetic multiplication and assignment. Overloadable -(`MulAssign`). -* `+` (`trait + trait`, `'a + trait`): compound type constraint. -* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`). -* `+=` (`var += expr`): arithmetic addition and assignment. Overloadable -(`AddAssign`). -* `,`: argument and element separator. -* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). -* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`). -* `-=` (`var -= expr`): arithmetic subtraction and assignment. Overloadable -(`SubAssign`). -* `->` (`fn(...) -> type`, `|...| -> type`): function and closure -return type. -* `.` (`expr.ident`): member access. -* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. -* `..` (`..expr`): struct literal update syntax. -* `..` (`variant(x, ..)`, `struct_type { x, .. }`): “and the rest” pattern -binding. -* `...` (`expr...expr`) *in a pattern*: inclusive range pattern. -* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`). -* `/=` (`var /= expr`): arithmetic division and assignment. Overloadable -(`DivAssign`). -* `:` (`pat: type`, `ident: type`): constraints. -* `:` (`ident: expr`): struct field initializer. -* `:` (`'a: loop {...}`): loop label. -* `;`: statement and item terminator. -* `;` (`[...; len]`): part of fixed-size array syntax -* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`). -* `<<=` (`var <<= expr`): left-shift and assignment. Overloadable (`ShlAssign`). -* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`). -* `<=` (`expr <= expr`): less-than or equal-to comparison. Overloadable -(`PartialOrd`). -* `=` (`var = expr`, `ident = type`): assignment/equivalence. -* `==` (`expr == expr`): equality comparison. Overloadable (`PartialEq`). -* `=>` (`pat => expr`): part of match arm syntax. -* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`). -* `>=` (`expr >= expr`): greater-than or equal-to comparison. Overloadable -(`PartialOrd`). -* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`). -* `>>=` (`var >>= expr`): right-shift and assignment. Overloadable -(`ShrAssign`). -* `@` (`ident @ pat`): pattern binding. -* `^` (`expr ^ expr`): bitwise exclusive OR. Overloadable (`BitXor`). -* `^=` (`var ^= expr`): bitwise exclusive OR and assignment. Overloadable -(`BitXorAssign`). -* `|` (`pat | pat`): pattern alternatives. -* `|` (`|…| expr`): closures. -* `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`). -* `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`). -* `||` (`expr || expr`): logical OR. -* `_`: “ignored” pattern binding. Also used to make integer literals readable. -* `?` (`expr?`): error propagation. +| Operator | Example | Explanation | Overloadable? | +|----------|---------|-------------|---------------| +| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro expansion | | +| `!` | `!expr` | Bitwise or logical complement | `Not` | +| `!=` | `var != expr` | Nonequality comparison | `PartialEq` | +| `%` | `expr % expr` | Arithmetic remainder | `Rem` | +| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemAssign` | +| `&` | `&expr`, `&mut expr` | Borrow | | +| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | Borrowed pointer type | | +| `&` | `expr & expr` | Bitwise AND | `BitAnd` | +| `&=` | `var &= expr` | Bitwise AND and assignment | `BitAndAssign` | +| `&&` | `expr && expr` | Logical AND | | +| `*` | `expr * expr` | Arithmetic multiplication | `Mul` | +| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulAssign` | +| `*` | `*expr` | Dereference | | +| `*` | `*const type`, `*mut type` | Raw pointer | | +| `+` | `trait + trait`, `'a + trait` | Compound type constraint | | +| `+` | `expr + expr` | Arithmetic addition | `Add` | +| `+=` | `var += expr` | Arithmetic addition and assignment | `AddAssign` | +| `,` | `expr, expr` | Argument and element separator | | +| `-` | `- expr` | Arithmetic negation | `Neg` | +| `-` | `expr - expr` | Arithmetic subtraction | `Sub` | +| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubAssign` | +| `->` | `fn(...) -> type`, \|...\| -> type | Function and closure return type | | +| `.` | `expr.ident` | Member access | | +| `..` | `..`, `expr..`, `..expr`, `expr..expr` | Right-exclusive range literal | | +| `..` | `..expr` | Struct literal update syntax | | +| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “And the rest” pattern binding | | +| `...` | `expr...expr` | In a pattern: inclusive range pattern | | +| `/` | `expr / expr` | Arithmetic division | `Div` | +| `/=` | `var /= expr` | Arithmetic division and assignment | `DivAssign` | +| `:` | `pat: type`, `ident: type` | Constraints | | +| `:` | `ident: expr` | Struct field initializer | | +| `:` | `'a: loop {...}` | Loop label | | +| `;` | `expr;` | Statement and item terminator | | +| `;` | `[...; len]` | Part of fixed-size array syntax | | +| `<<` | `expr << expr` | Left-shift | `Shl` | +| `<<=` | `var <<= expr` | Left-shift and assignment | `ShlAssign` | +| `<` | `expr < expr` | Less than comparison | `PartialOrd` | +| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` | +| `=` | `var = expr`, `ident = type` | Assignment/equivalence | | +| `==` | `expr == expr` | Equality comparison | `PartialEq` | +| `=>` | `pat => expr` | Part of match arm syntax | | +| `>` | `expr > expr` | Greater than comparison | `PartialOrd` | +| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` | +| `>>` | `expr >> expr` | Right-shift | `Shr` | +| `>>=` | `var >>= expr` | Right-shift and assignment | `ShrAssign` | +| `@` | `ident @ pat` | Pattern binding | | +| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` | +| `^=` | `var ^= expr` | Bitwise exclusive OR and assignment | `BitXorAssign` | +| \| | pat \| pat | Pattern alternatives | | +| \| | expr \| expr | Bitwise OR | `BitOr` | +| \|= | var \|= expr | Bitwise OR and assignment | `BitOrAssign` | +| \|\| | expr \|\| expr | Logical OR | | +| `?` | `expr?` | Error propagation | | ### Non-operator Symbols The following list contains all non-letters that don’t function as operators; that is, they don’t behave like a function or method call. -#### Stand-Alone Syntax +Table B-2 shows symbols that appear on their own and are valid in a variety of +locations. -* `'ident`: named lifetime or loop label. -* `...u8`, `...i32`, `...f64`, `...usize`, *etc.*: numeric literal of -specific type. -* `"..."`: string literal. -* `r"..."`, `r#"..."#`, `r##"..."##`, *etc.*: raw string literal, -escape characters are not processed. -* `b"..."`: byte string literal, constructs a `[u8]` instead of a string. -* `br"..."`, `br#"..."#`, `br##"..."##`, *etc.*: raw byte string -literal, combination of raw and byte string literal. -* `'...'`: character literal. -* `b'...'`: ASCII byte literal. -* `|...| expr`: closure. -* `!`: always empty bottom type for diverging functions. +Table B-2: Stand-Alone Syntax -#### Path-Related Syntax +| Symbol | Explanation | +|--------|-------------| +| `'ident` | Named lifetime or loop label | +| `...u8`, `...i32`, `...f64`, `...usize`, etc. | Numeric literal of specific type | +| `"..."` | String literal | +| `r"..."`, `r#"..."#`, `r##"..."##`, etc. | Raw string literal, escape characters not processed | +| `b"..."` | Byte string literal; constructs a `[u8]` instead of a string | +| `br"..."`, `br#"..."#`, `br##"..."##`, etc. | Raw byte string literal, combination of raw and byte string literal | +| `'...'` | Character literal | +| `b'...'` | ASCII byte literal | +| \|...\| expr | Closure | +| `!` | Always empty bottom type for diverging functions | +| `_` | “Ignored” pattern binding; also used to make integer literals readable | -* `ident::ident`: namespace path. -* `::path`: path relative to the crate root (*i.e.*, an explicitly absolute -path). -* `self::path`: path relative to the current module (*i.e.*, an explicitly -relative path). -* `super::path`: path relative to the parent of the current module. -* `type::ident`, `::ident`: associated constants, functions, and -types. -* `::...`: associated item for a type that cannot be directly named -(*e.g.*, `<&T>::...`, `<[T]>::...`, *etc.*). -* `trait::method(...)`: disambiguating a method call by naming the trait -that defines it. -* `type::method(...)`: disambiguating a method call by naming the type for -which it’s defined. -* `::method(...)`: disambiguating a method call by naming -the trait *and* type. +Table B-3 shows symbols that appear in the context of a path through the module +hierarchy to an item. -#### Generics +Table B-3: Path-Related Syntax -* `path<...>` (*e.g.*, `Vec`): specifies parameters to generic type *in -a type*. -* `path::<...>`, `method::<...>` (*e.g.*, `"42".parse::()`): -specifies parameters to generic type, function, or method *in an expression*. -Often referred to as *turbofish*. -* `fn ident<...> ...`: define generic function. -* `struct ident<...> ...`: define generic structure. -* `enum ident<...> ...`: define generic enumeration. -* `impl<...> ...`: define generic implementation. -* `for<...> type`: higher-ranked lifetime bounds. -* `type` (*e.g.*, `Iterator`): a generic type where one or -more associated types have specific assignments. +| Symbol | Explanation | +|--------|-------------| +| `ident::ident` | Namespace path | +| `::path` | Path relative to the crate root (i.e., an explicitly absolute path) | +| `self::path` | Path relative to the current module (i.e., an explicitly relative path). +| `super::path` | Path relative to the parent of the current module | +| `type::ident`, `::ident` | Associated constants, functions, and types | +| `::...` | Associated item for a type that cannot be directly named (e.g., `<&T>::...`, `<[T]>::...`, etc.) | +| `trait::method(...)` | Disambiguating a method call by naming the trait that defines it | +| `type::method(...)` | Disambiguating a method call by naming the type for which it’s defined | +| `::method(...)` | Disambiguating a method call by naming the trait and type | -#### Trait Bound Constraints +Table B-4 shows symbols that appear in the context of using generic type +parameters. -* `T: U`: generic parameter `T` constrained to types that implement `U`. -* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type -“outlives” the lifetime, we mean it cannot transitively contain any references -with lifetimes shorter than `'a`. -* `T : 'static`: the generic type `T` contains no borrowed references other -than `'static` ones. -* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`. -* `T: ?Sized`: allow generic type parameter to be a dynamically sized type. -* `'a + trait`, `trait + trait`: compound type constraint. +Table B-4: Generics -#### Macros and Attributes +| Symbol | Explanation | +|--------|-------------| +| `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec`) | +| `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., `"42".parse::()`) | +| `fn ident<...> ...` | Define generic function | +| `struct ident<...> ...` | Define generic structure | +| `enum ident<...> ...` | Define generic enumeration | +| `impl<...> ...` | Define generic implementation | +| `for<...> type` | Higher-ranked lifetime bounds | +| `type` | A generic type where one or more associated types have specific assignments (e.g., `Iterator`) | -* `#[meta]`: outer attribute. -* `#![meta]`: inner attribute. -* `$ident`: macro substitution. -* `$ident:kind`: macro capture. -* `$(…)…`: macro repetition. +Table B-5 shows symbols that appear in the context of constraining generic type +parameters with trait bounds. -#### Comments +Table B-5: Trait Bound Constraints -* `//`: line comment. -* `//!`: inner line doc comment. -* `///`: outer line doc comment. -* `/*...*/`: block comment. -* `/*!...*/`: inner block doc comment. -* `/**...*/`: outer block doc comment. +| Symbol | Explanation | +|--------|-------------| +| `T: U` | Generic parameter `T` constrained to types that implement `U` | +| `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type cannot transitively contain any references with lifetimes shorter than `'a`) | +| `T : 'static` | Generic type `T` contains no borrowed references other than `'static` ones | +| `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` | +| `T: ?Sized` | Allow generic type parameter to be a dynamically sized type | +| `'a + trait`, `trait + trait` | Compound type constraint | -#### Tuples +Table B-6 shows symbols that appear in the context of calling or defining +macros and specifying attributes on an item. -* `()`: empty tuple (*aka* unit), both literal and type. -* `(expr)`: parenthesized expression. -* `(expr,)`: single-element tuple expression. -* `(type,)`: single-element tuple type. -* `(expr, ...)`: tuple expression. -* `(type, ...)`: tuple type. -* `expr(expr, ...)`: function call expression. Also used to initialize -tuple `struct`s and tuple `enum` variants. -* `ident!(...)`, `ident!{...}`, `ident![...]`: macro invocation. -* `expr.0`, `expr.1`, *etc.*: tuple indexing. +Table B-6: Macros and Attributes -#### Curly Brackets +| Symbol | Explanation | +|--------|-------------| +| `#[meta]` | Outer attribute | +| `#![meta]` | Inner attribute | +| `$ident` | Macro substitution | +| `$ident:kind` | Macro capture | +| `$(…)…` | Macro repetition | -* `{...}`: block expression. -* `Type {...}`: `struct` literal. +Table B-7 shows symbols that create comments. -#### Square Brackets +Table B-7: Comments -* `[...]`: array literal. -* `[expr; len]`: array literal containing `len` copies of `expr`. -* `[type; len]`: array type containing `len` instances of `type`. -* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`). -* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing -pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or -`RangeFull` as the “index.” +| Symbol | Explanation | +|--------|-------------| +| `//` | Line comment | +| `//!` | Inner line doc comment | +| `///` | Outer line doc comment | +| `/*...*/` | Block comment | +| `/*!...*/` | Inner block doc comment | +| `/**...*/` | Outer block doc comment | + +Table B-8 shows symbols that appear in the context of using tuples. + +Table B-8: Tuples + +| Symbol | Explanation | +|--------|-------------| +| `()` | Empty tuple (aka unit), both literal and type | +| `(expr)` | Parenthesized expression | +| `(expr,)` | Single-element tuple expression | +| `(type,)` | Single-element tuple type | +| `(expr, ...)` | Tuple expression | +| `(type, ...)` | Tuple type | +| `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants | +| `ident!(...)`, `ident!{...}`, `ident![...]` | Macro invocation | +| `expr.0`, `expr.1`, etc. | Tuple indexing | + +Table B-9 shows the contexts in which curly braces are used. + +Table B-9: Curly Brackets + +| Context | Explanation | +|---------|-------------| +| `{...}` | Block expression | +| `Type {...}` | `struct` literal | + +Table B-10 shows the contexts in which square brackets are used. + +Table B-10: Square Brackets + +| Context | Explanation | +|---------|-------------| +| `[...]` | Array literal | +| `[expr; len]` | Array literal containing `len` copies of `expr` | +| `[type; len]` | Array type containing `len` instances of `type` | +| `expr[expr]` | Collection indexing. Overloadable (`Index`, `IndexMut`) | +| `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | Collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the “index” | diff --git a/src/doc/book/second-edition/src/appendix-03-derivable-traits.md b/src/doc/book/second-edition/src/appendix-03-derivable-traits.md index 906cc8f05b..c4b996ffdb 100644 --- a/src/doc/book/second-edition/src/appendix-03-derivable-traits.md +++ b/src/doc/book/second-edition/src/appendix-03-derivable-traits.md @@ -1,10 +1,10 @@ ## Appendix C: Derivable Traits -In various places in the book, we’ve discussed the `derive` attribute that you -can apply to a struct or enum definition. +In various places in the book, we’ve discussed the `derive` attribute, which +you can apply to a struct or enum definition. The `derive` attribute generates +code that will implement a trait with its own default implementation on the +type you’ve annotated with the `derive` syntax. -The `derive` attribute generates code that will implement a trait with its own -default implementation on the type you’ve annotated with the `derive` syntax. In this appendix, we provide a reference of all the traits in the standard library that you can use with `derive`. Each section covers: @@ -25,15 +25,15 @@ trying to accomplish. An example of a trait that can’t be derived is `Display`, which handles formatting for end users. You should always consider the appropriate way to -display a type to an end user: for example, what parts of the type should an -end user be allowed to see? What parts would they find relevant? What format of -the data would be most relevant to them? The Rust compiler doesn’t have this -insight, so it can’t provide appropriate default behavior for you. +display a type to an end user. What parts of the type should an end user be +allowed to see? What parts would they find relevant? What format of the data +would be most relevant to them? The Rust compiler doesn’t have this insight, so +it can’t provide appropriate default behavior for you. The list of derivable traits provided in this appendix is not comprehensive: libraries can implement `derive` for their own traits, making the list of traits you can use `derive` with truly open-ended. Implementing `derive` -involves using a procedural macro, which is covered in Appendix D, “Macros.” +involves using a procedural macro, which is covered in Appendix D. ### `Debug` for Programmer Output @@ -54,9 +54,9 @@ The `PartialEq` trait allows you to compare instances of a type to check for equality and enables use of the `==` and `!=` operators. Deriving `PartialEq` implements the `eq` method. When `PartialEq` is derived on -structs, two instances are equal only if *all* fields are equal and not equal -if any fields are not equal. When derived on enums, each variant is equal to -itself and not equal to the other variants. +structs, two instances are equal only if *all* fields are equal, and the +instances are not equal if any fields are not equal. When derived on enums, +each variant is equal to itself and not equal to the other variants. The `PartialEq` trait is required, for example, with the use of the `assert_eq!` macro, which needs to be able to compare two instances of a type @@ -69,8 +69,8 @@ implement `PartialEq` can implement `Eq`. One example of this is floating point number types: the implementation of floating point numbers states that two instances of the not-a-number (`NaN`) value are not equal to each other. -An example of when `Eq` is required is for keys in a `HashMap` so the `HashMap` -can tell whether two keys are the same. +An example of when `Eq` is required is for keys in a `HashMap` so the +`HashMap` can tell whether two keys are the same. ### `PartialOrd` and `Ord` for Ordering Comparisons @@ -146,13 +146,13 @@ code might be slower or have to use `clone` in places. ### `Hash` for Mapping a Value to a Value of Fixed Size The `Hash` trait allows you to take an instance of a type of arbitrary size and -map that instance to a value of fixed size, using a hash function. Deriving +map that instance to a value of fixed size using a hash function. Deriving `Hash` implements the `hash` method. The derived implementation of the `hash` method combines the result of calling `hash` on each of the parts of the type, meaning all fields or values must also implement `Hash` to derive `Hash`. -An example of when `Hash` is required is in storing keys in a `HashMap` to -store data efficiently. +An example of when `Hash` is required is in storing keys in a `HashMap` +to store data efficiently. ### `Default` for Default Values @@ -168,7 +168,7 @@ Struct Update Syntax” section in Chapter 5. You can customize a few fields of struct and then set and use a default value for the rest of the fields by using `..Default::default()`. -The `Default` trait is required when, for example, you use the -`unwrap_or_default` method on `Option` instances. If the `Option` is -`None`, the `unwrap_or_default` method will return the result of -`Default::default` for the type `T` stored in the `Option`. +The `Default` trait is required when you use the method `unwrap_or_default` on +`Option` instances, for example. If the `Option` is `None`, the method +`unwrap_or_default` will return the result of `Default::default` for the type +`T` stored in the `Option`. diff --git a/src/doc/book/second-edition/src/appendix-04-macros.md b/src/doc/book/second-edition/src/appendix-04-macros.md index 54707da61d..0b5e32592f 100644 --- a/src/doc/book/second-edition/src/appendix-04-macros.md +++ b/src/doc/book/second-edition/src/appendix-04-macros.md @@ -11,11 +11,11 @@ follows: We’re covering the details of macros in an appendix because they’re still evolving in Rust. Macros have changed and, in the near future, will change at a quicker rate than the rest of the language and standard library since Rust 1.0, -so this section is more likely to date than the rest of the book. Due to Rust’s -stability guarantees, the code shown here will continue to work with future -versions. But there may be additional capabilities or easier ways to write -macros that weren’t available at the time of this publication. Bear that in -mind when you try to implement anything from this appendix. +so this section is more likely to become out-of-date than the rest of the book. +Due to Rust’s stability guarantees, the code shown here will continue to work +with future versions, but there may be additional capabilities or easier ways +to write macros that weren’t available at the time of this publication. Bear +that in mind when you try to implement anything from this appendix. ### The Difference Between Macros and Functions @@ -90,11 +90,11 @@ let v: Vec = vec![1, 2, 3]; ``` We could also use the `vec!` macro to make a vector of two integers or a vector -of five string slices: we wouldn’t be able to use a function to do the same +of five string slices. We wouldn’t be able to use a function to do the same because we wouldn’t know the number or type of values up front. Let’s look at a slightly simplified definition of the `vec!` macro in Listing -D-1: +D-1. ```rust #[macro_export] @@ -309,12 +309,6 @@ To start defining the procedural macro, place the code in Listing D-3 into your *src/lib.rs* file for the `hello_macro_derive` crate. Note that this code won’t compile until we add a definition for the `impl_hello_macro` function. -Notice the way we’ve split the functions in D-3; this will be the same for -almost every procedural macro crate you see or create, because it makes writing -a procedural macro more convenient. What you choose to do in the place where -the `impl_hello_macro` function is called will be different depending on your -procedural macro’s purpose. - Filename: hello_macro_derive/src/lib.rs ```rust,ignore @@ -344,6 +338,12 @@ pub fn hello_macro_derive(input: TokenStream) -> TokenStream { Listing D-3: Code that most procedural macro crates will need to have for processing Rust code +Notice the way we’ve split the functions in D-3; this will be the same for +almost every procedural macro crate you see or create, because it makes writing +a procedural macro more convenient. What you choose to do in the place where +the `impl_hello_macro` function is called will be different depending on your +procedural macro’s purpose. + We’ve introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The `proc_macro` crate comes with Rust, so we didn’t need to add that to the dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust @@ -403,7 +403,7 @@ where we’ll build the new Rust code we want to include. But before we do, note that the last part of this `hello_macro_derive` function uses the `parse` function from the `quote` crate to turn the output of the `impl_hello_macro` function back into a `TokenStream`. The returned `TokenStream` is added to the -code that our crate users write, so when they compile their crate, they get +code that our crate users write, so when they compile their crate, they’ll get extra functionality that we provide. You might have noticed that we’re calling `unwrap` to panic if the calls to the @@ -439,7 +439,7 @@ annotated type using `ast.ident`. The code in Listing D-2 specifies that the The `quote!` macro lets us write the Rust code that we want to return and convert it into `quote::Tokens`. This macro also provides some very cool -templating mechanics; we can write `#name` and `quote!` will replace it with +templating mechanics; we can write `#name`, and `quote!` will replace it with the value in the variable named `name`. You can even do some repetition similar to the way regular macros work. Check out [the `quote` crate’s docs][quote-docs] for a thorough introduction. diff --git a/src/doc/book/second-edition/src/appendix-05-translation.md b/src/doc/book/second-edition/src/appendix-05-translation.md index a3e029e3c4..96abac652a 100644 --- a/src/doc/book/second-edition/src/appendix-05-translation.md +++ b/src/doc/book/second-edition/src/appendix-05-translation.md @@ -11,7 +11,7 @@ For resources in languages other than English. Most are still in progress; see - [简体中文](http://www.broadview.com.cn/article/144), [alternate](https://github.com/KaiserY/trpl-zh-cn) - [Українська](https://github.com/pavloslav/rust-book-uk-ua) - [Español](https://github.com/thecodix/book) -- [Italiano](https://github.com/CodelessFuture/trpl2-it) +- [Italiano](https://github.com/AgeOfWar/rust-book-it) - [Русский](https://github.com/iDeBugger/rust-book-ru) - [한국어](https://github.com/rinthel/rust-lang-book-ko) - [日本語](https://github.com/hazama-yuinyan/book) diff --git a/src/doc/book/second-edition/src/appendix-07-nightly-rust.md b/src/doc/book/second-edition/src/appendix-07-nightly-rust.md index 3eaf697afa..a16f1da911 100644 --- a/src/doc/book/second-edition/src/appendix-07-nightly-rust.md +++ b/src/doc/book/second-edition/src/appendix-07-nightly-rust.md @@ -150,7 +150,7 @@ $ rustup install nightly You can see all of the *toolchains* (releases of Rust and associated components) you have installed with `rustup` as well. Here’s an example on one -of your authors’ computers: +of your authors’ Windows computer: ```powershell > rustup toolchain list diff --git a/src/doc/book/second-edition/src/ch00-00-introduction.md b/src/doc/book/second-edition/src/ch00-00-introduction.md index 8d8d7be789..21db273bd6 100644 --- a/src/doc/book/second-edition/src/ch00-00-introduction.md +++ b/src/doc/book/second-edition/src/ch00-00-introduction.md @@ -28,7 +28,7 @@ is prone to a variety of subtle bugs, which in most other languages can be caught only through extensive testing and careful code review by experienced developers. In Rust, the compiler plays a gatekeeper role by refusing to compile code with these elusive bugs, including concurrency bugs. By working -alongside the compiler, the team can spend more time focusing on the program’s +alongside the compiler, the team can spend their time focusing on the program’s logic rather than chasing down bugs. Rust also brings contemporary developer tools to the systems programming world: @@ -104,17 +104,17 @@ chapters. In concept chapters, you’ll learn about an aspect of Rust. In projec chapters, we’ll build small programs together, applying what you’ve learned so far. Chapters 2, 12, and 20 are project chapters; the rest are concept chapters. -Chapter 1 explains how to install Rust, how to write a "Hello, world!" program, -and how to use Cargo, Rust's package manager and build tool. Chapter 2 is a +Chapter 1 explains how to install Rust, how to write a Hello, world! program, +and how to use Cargo, Rust’s package manager and build tool. Chapter 2 is a hands-on introduction to the Rust language. Here we cover concepts at a high level, and later chapters will provide additional detail. If you want to get your hands dirty right away, Chapter 2 is the place for that. At first, you -might even want to skip Chapter 3, which covers Rust features similar to other -programming language features, and head straight to Chapter 4 to learn about +might even want to skip Chapter 3, which covers Rust features similar to those +of other programming languages, and head straight to Chapter 4 to learn about Rust’s ownership system. However, if you’re a particularly meticulous learner who prefers to learn every detail before moving on to the next, you might want to skip Chapter 2 and go straight to Chapter 3, returning to Chapter 2 when -you’d like to work on a project applying the details you've learned. +you’d like to work on a project applying the details you’ve learned. Chapter 5 discusses structs and methods, and Chapter 6 covers enums, `match` expressions, and the `if let` control flow construct. You’ll use structs and @@ -164,9 +164,9 @@ confusion. But do whatever works for you. An important part of the process of learning Rust is learning how to read the error messages the compiler displays: these will guide you toward working code. -As such, we’ll provide many examples of code that don’t compile along with the -error message the compiler will show you in each situation. Know that if you -enter and run a random example, it may not compile! Make sure you read the +As such, we’ll provide many examples of code that doesn’t compile along with +the error message the compiler will show you in each situation. Know that if +you enter and run a random example, it may not compile! Make sure you read the surrounding text to see whether the example you’re trying to run is meant to error. In most situations, we’ll lead you to the correct version of any code that doesn’t compile. @@ -176,4 +176,4 @@ that doesn’t compile. The source files from which this book is generated can be found on [GitHub][book]. -[book]: https://github.com/rust-lang/book/tree/master/second-edition/src \ No newline at end of file +[book]: https://github.com/rust-lang/book/tree/master/second-edition/src diff --git a/src/doc/book/second-edition/src/ch01-00-getting-started.md b/src/doc/book/second-edition/src/ch01-00-getting-started.md index 49cce6ffc9..ff5e324f7a 100644 --- a/src/doc/book/second-edition/src/ch01-00-getting-started.md +++ b/src/doc/book/second-edition/src/ch01-00-getting-started.md @@ -1,7 +1,8 @@ # Getting Started -Let’s start your Rust journey! In this chapter, we’ll discuss: +Let’s start your Rust journey! There’s a lot to learn, but every journey starts +somewhere. In this chapter, we’ll discuss: * Installing Rust on Linux, macOS, and Windows -* Writing a program that prints “Hello, world!” +* Writing a program that prints `Hello, world!` * Using `cargo`, Rust’s package manager and build system diff --git a/src/doc/book/second-edition/src/ch01-01-installation.md b/src/doc/book/second-edition/src/ch01-01-installation.md index b8116e8eec..d0e5e1fdac 100644 --- a/src/doc/book/second-edition/src/ch01-01-installation.md +++ b/src/doc/book/second-edition/src/ch01-01-installation.md @@ -4,6 +4,9 @@ The first step is to install Rust. We’ll download Rust through `rustup`, a command line tool for managing Rust versions and associated tools. You’ll need an internet connection for the download. +> Note: If you prefer not to use `rustup` for some reason, please see [the Rust +> installation page](https://www.rust-lang.org/install.html) for other options. + The following steps install the latest stable version of the Rust compiler. All the examples and output in this book use stable Rust 1.21.0. Rust’s stability guarantees ensure that all the examples in the book that compile will continue @@ -17,12 +20,11 @@ work as expected with the content of this book. > In this chapter and throughout the book, we’ll show some commands used in the > terminal. Lines that you should enter in a terminal all start with `$`. You > don’t need to type in the `$` character; it indicates the start of each -> command. Many tutorials use the convention `$` for commands you run as a -> regular user and `#` for commands you run as an administrator. Lines that -> don’t start with `$` typically show the output of the previous command. -> Additionally, PowerShell specific examples will use `>` rather than `$`. +> command. Lines that don’t start with `$` typically show the output of the +> previous command. Additionally, PowerShell-specific examples will use `>` +> rather than `$`. -### Installing Rustup on Linux or macOS +### Installing `rustup` on Linux or macOS If you’re using Linux or macOS, open a terminal and enter the following command: @@ -38,8 +40,8 @@ for your password. If the install is successful, the following line will appear: Rust is installed now. Great! ``` -Of course, if you distrust using `curl URL | sh` to install software, you can -download, inspect, and run the script however you like. +If you prefer, feel free to download the script and inspect it before running +it. The installation script automatically adds Rust to your system PATH after your next login. If you want to start using Rust right away instead of restarting @@ -58,32 +60,27 @@ $ export PATH="$HOME/.cargo/bin:$PATH" Additionally, you’ll need a linker of some kind. It’s likely one is already installed, but when you try to compile a Rust program and get errors indicating -that a linker could not execute, you’ll need to install one. You can install a -C compiler, because that will usually come with the correct linker. Check your -platform’s documentation for how to install a C compiler. Some common Rust -packages depend on C code and will need a C compiler too, so it might be worth -installing one now regardless. +that a linker could not execute, that means a linker isn’t installed on your +system and you’ll need to install one manually. C compilers usually come with +the correct linker. Check your platform’s documentation for how to install a C +compiler. Also, some common Rust packages depend on C code and will need a C +compiler. Therefore, it might be worth installing one now. -### Installing Rustup on Windows +### Installing `rustup` on Windows -On Windows, go to [https://www.rust-lang.org/en-US/install.html][install] and -follow the instructions for installing Rust. At some point in the installation, -you’ll receive a message explaining that you’ll also need the C++ build tools -for Visual Studio 2013 or later. The easiest way to acquire the build tools is -to install [Build Tools for Visual Studio 2017][visualstudio]. The tools are in +On Windows, go to [https://www.rust-lang.org/install.html][install] and follow +the instructions for installing Rust. At some point in the installation, you’ll +receive a message explaining that you’ll also need the C++ build tools for +Visual Studio 2013 or later. The easiest way to acquire the build tools is to +install [Build Tools for Visual Studio 2017][visualstudio]. The tools are in the Other Tools and Frameworks section. -[install]: https://www.rust-lang.org/en-US/install.html +[install]: https://www.rust-lang.org/install.html [visualstudio]: https://www.visualstudio.com/downloads/ The rest of this book uses commands that work in both *cmd.exe* and PowerShell. If there are specific differences, we’ll explain which to use. -### Custom Installations Without Rustup - -If you prefer not to use `rustup` for some reason, please see [the Rust -installation page](https://www.rust-lang.org/install.html) for other options. - ### Updating and Uninstalling After you’ve installed Rust via `rustup`, updating to the latest version is diff --git a/src/doc/book/second-edition/src/ch01-02-hello-world.md b/src/doc/book/second-edition/src/ch01-02-hello-world.md index dbc6b3a86c..ec160b7d57 100644 --- a/src/doc/book/second-edition/src/ch01-02-hello-world.md +++ b/src/doc/book/second-edition/src/ch01-02-hello-world.md @@ -2,10 +2,10 @@ Now that you’ve installed Rust, let’s write your first Rust program. It’s traditional when learning a new language to write a little program that prints -the text “Hello, world!” to the screen, so we’ll do the same here! +the text `Hello, world!` to the screen, so we’ll do the same here! > Note: This book assumes basic familiarity with the command line. Rust makes -> no specific demands about your editing, tooling, or where your code lives, so +> no specific demands about your editing or tooling or where your code lives, so > if you prefer to use an integrated development environment (IDE) instead of > the command line, feel free to use your favorite IDE. Many IDEs now have some > degree of Rust support; check the IDE’s documentation for details. Recently, @@ -20,7 +20,7 @@ we suggest making a *projects* directory in your home directory and keeping all your projects there. Open a terminal and enter the following commands to make a *projects* directory -and a directory for the “Hello, world!” project within the *projects* directory. +and a directory for the Hello, world! project within the *projects* directory. For Linux and macOS, enter this: @@ -56,7 +56,7 @@ the *.rs* extension. If you’re using more than one word in your filename, use an underscore to separate them. For example, use *hello_world.rs* rather than *helloworld.rs*. -Now open the *main.rs* file you just created, and enter the code in Listing 1-1. +Now open the *main.rs* file you just created and enter the code in Listing 1-1. Filename: main.rs @@ -66,9 +66,9 @@ fn main() { } ``` -Listing 1-1: A program that prints “Hello, world!” +Listing 1-1: A program that prints `Hello, world!` -Save the file, and go back to your terminal window. On Linux or macOS, enter +Save the file and go back to your terminal window. On Linux or macOS, enter the following commands to compile and run the file: ```text @@ -77,7 +77,7 @@ $ ./main Hello, world! ``` -On Windows, enter the command `.\main.exe` instead of `./main`. +On Windows, enter the command `.\main.exe` instead of `./main`: ```powershell > rustc main.rs @@ -90,11 +90,11 @@ the terminal. If you don’t see this output, refer back to the “Troubleshooti section for ways to get help. If `Hello, world!` did print, congratulations! You’ve officially written a Rust -program. That makes you a Rust programmer! Welcome! +program. That makes you a Rust programmer—welcome! ### Anatomy of a Rust Program -Let’s review in detail what just happened in your “Hello, world!” program. +Let’s review in detail what just happened in your Hello, world! program. Here’s the first piece of the puzzle: ```rust @@ -103,21 +103,20 @@ fn main() { } ``` -These lines define a *function* in Rust. The `main` function is special: it is +These lines define a function in Rust. The `main` function is special: it is always the first code that runs in every executable Rust program. The first line declares a function named `main` that has no parameters and returns -nothing. If there were parameters, they would go inside the parentheses, `(` -and `)`. +nothing. If there were parameters, they would go inside the parentheses, `()`. -Also, note that the function body is wrapped in curly brackets, `{` and `}`. -Rust requires these around all function bodies. It’s good style to place the -opening curly bracket on the same line as the function declaration, adding one -space in between. +Also, note that the function body is wrapped in curly brackets, `{}`. Rust +requires these around all function bodies. It’s good style to place the opening +curly bracket on the same line as the function declaration, adding one space in +between. At the time of this writing, an automatic formatter tool called `rustfmt` is under development. If you want to stick to a standard style across Rust projects, `rustfmt` will format your code in a particular style. The Rust team -plans to eventually include it with the standard Rust distribution, like +plans to eventually include this tool with the standard Rust distribution, like `rustc`. So depending on when you read this book, it might already be installed on your computer! Check the online documentation for more details. @@ -131,15 +130,15 @@ This line does all the work in this little program: it prints text to the screen. There are four important details to notice here. First, Rust style is to indent with four spaces, not a tab. -Second, `println!` calls a Rust *macro*. If it called a function instead, it +Second, `println!` calls a Rust macro. If it called a function instead, it would be entered as `println` (without the `!`). We’ll discuss Rust macros in more detail in Appendix D. For now, you just need to know that using a `!` means that you’re calling a macro instead of a normal function. -Third, you see the `"Hello, world!"` *string*. We pass this string as an -argument to `println!`, and the string is printed to the screen. +Third, you see the `"Hello, world!"` string. We pass this string as an argument +to `println!`, and the string is printed to the screen. -Fourth, we end the line with a semicolon `;`, which indicates that this +Fourth, we end the line with a semicolon (`;`), which indicates that this expression is over and the next one is ready to begin. Most lines of Rust code end with a semicolon. @@ -185,13 +184,13 @@ here, you run the *main* or *main.exe* file, like this: $ ./main # or .\main.exe on Windows ``` -If *main.rs* was your “Hello, world!” program, this line would print `Hello, +If *main.rs* was your Hello, world! program, this line would print `Hello, world!` to your terminal. If you’re more familiar with a dynamic language, such as Ruby, Python, or JavaScript, you might not be used to compiling and running a program as separate steps. Rust is an *ahead-of-time compiled* language, meaning you can -compile a program, give the executable to someone else, and they can run it +compile a program and give the executable to someone else, and they can run it even without having Rust installed. If you give someone a *.rb*, *.py*, or *.js* file, they need to have a Ruby, Python, or JavaScript implementation installed (respectively). But in those languages, you only need one command to diff --git a/src/doc/book/second-edition/src/ch01-03-hello-cargo.md b/src/doc/book/second-edition/src/ch01-03-hello-cargo.md index 2e794f74f1..d4f36c5225 100644 --- a/src/doc/book/second-edition/src/ch01-03-hello-cargo.md +++ b/src/doc/book/second-edition/src/ch01-03-hello-cargo.md @@ -6,9 +6,9 @@ such as building your code, downloading the libraries your code depends on, and building those libraries. (We call libraries your code needs *dependencies*.) The simplest Rust programs, like the one we’ve written so far, don’t have any -dependencies. So if we had built the “Hello, world!” project with Cargo, it -would only use the part of Cargo that handles building your code. As you write -more complex Rust programs, you’ll add dependencies, and if you start a project +dependencies. So if we had built the Hello, world! project with Cargo, it would +only use the part of Cargo that handles building your code. As you write more +complex Rust programs, you’ll add dependencies, and if you start a project using Cargo, adding dependencies will be much easier to do. Because the vast majority of Rust projects use Cargo, the rest of this book @@ -28,9 +28,9 @@ determine how to install Cargo separately. ### Creating a Project with Cargo Let’s create a new project using Cargo and look at how it differs from our -original “Hello, world!” project. Navigate back to your *projects* directory -(or wherever you decided to store your code). Then, on any operating system, -run the following: +original Hello, world! project. Navigate back to your *projects* directory (or +wherever you decided to store your code). Then, on any operating system, run +the following: ```text $ cargo new hello_cargo --bin @@ -68,8 +68,8 @@ authors = ["Your Name "] Listing 1-2: Contents of *Cargo.toml* generated by `cargo new` -This file is in the [*TOML*][toml] (Tom’s Obvious, Minimal -Language) format, which is Cargo’s configuration format. +This file is in the [*TOML*][toml] (*Tom’s Obvious, Minimal +Language*) format, which is Cargo’s configuration format. [toml]: https://github.com/toml-lang/toml @@ -97,10 +97,10 @@ fn main() { } ``` -Cargo has generated a “Hello, world!” program for you, just like the one we -wrote in Listing 1-1! So far, the differences between our previous project and -the project Cargo generates are that Cargo placed the code in the *src* -directory, and we have a *Cargo.toml* configuration file in the top directory. +Cargo has generated a Hello, world! program for you, just like the one we wrote +in Listing 1-1! So far, the differences between our previous project and the +project Cargo generates are that Cargo placed the code in the *src* directory, +and we have a *Cargo.toml* configuration file in the top directory. Cargo expects your source files to live inside the *src* directory. The top-level project directory is just for README files, license information, @@ -115,7 +115,7 @@ file. ### Building and Running a Cargo Project -Now let’s look at the difference when we build and run the “Hello, world!” +Now let’s look at what’s different when we build and run the Hello, world! program with Cargo! From your *hello_cargo* directory, build your project by entering the following command: @@ -181,12 +181,12 @@ speed up the process! As such, many Rustaceans run `cargo check` periodically as they write their program to make sure it compiles. Then they run `cargo build` when they’re ready to use the executable. -To recap what we’ve learned so far about Cargo: +Let’s recap what we’ve learned so far about Cargo: * We can build a project using `cargo build` or `cargo check`. * We can build and run a project in one step using `cargo run`. -* Instead of the result of the build being saved in the same directory as our -code, Cargo stores it in the *target/debug* directory. +* Instead of saving the result of the build in the same directory as our code, + Cargo stores it in the *target/debug* directory. An additional advantage of using Cargo is that the commands are the same no matter which operating system you’re working on. So, at this point, we’ll no @@ -199,7 +199,7 @@ When your project is finally ready for release, you can use `cargo build executable in *target/release* instead of *target/debug*. The optimizations make your Rust code run faster, but turning them on lengthens the time it takes for your program to compile. This is why there are two different profiles: one -for development when you want to rebuild quickly and often, and another for +for development, when you want to rebuild quickly and often, and another for building the final program you’ll give to a user that won’t be rebuilt repeatedly and that will run as fast as possible. If you’re benchmarking your code’s running time, be sure to run `cargo build --release` and benchmark with @@ -235,11 +235,10 @@ you’ve learned how to: * Install the latest stable version of Rust using `rustup` * Update to a newer Rust version * Open locally installed documentation -* Write and run a “Hello, world!” program using `rustc` directly +* Write and run a Hello, world! program using `rustc` directly * Create and run a new project using the conventions of Cargo This is a great time to build a more substantial program to get used to reading -and writing Rust code. So, in the next chapter, we’ll build a guessing game -program. If you would rather start by learning how common programming concepts -work in Rust, see Chapter 3, and then return to Chapter 2. - +and writing Rust code. So, in Chapter 2, we’ll build a guessing game program. +If you would rather start by learning how common programming concepts work in +Rust, see Chapter 3 and then return to Chapter 2. diff --git a/src/doc/book/second-edition/src/ch02-00-guessing-game-tutorial.md b/src/doc/book/second-edition/src/ch02-00-guessing-game-tutorial.md index 60c6da84d6..8c7d9c32d9 100644 --- a/src/doc/book/second-edition/src/ch02-00-guessing-game-tutorial.md +++ b/src/doc/book/second-edition/src/ch02-00-guessing-game-tutorial.md @@ -170,7 +170,7 @@ let mut bar = 5; // mutable > line. Rust ignores everything in comments, which are discussed in more detail > in Chapter 3. -Let's return to the guessing game program. You now know that `let mut guess` +Let’s return to the guessing game program. You now know that `let mut guess` will introduce a mutable variable named `guess`. On the other side of the equal sign (`=`) is the value that `guess` is bound to, which is the result of calling `String::new`, a function that returns a new instance of a `String`. diff --git a/src/doc/book/second-edition/src/ch04-03-slices.md b/src/doc/book/second-edition/src/ch04-03-slices.md index c2701ba9f2..ee7a61c468 100644 --- a/src/doc/book/second-edition/src/ch04-03-slices.md +++ b/src/doc/book/second-edition/src/ch04-03-slices.md @@ -159,7 +159,7 @@ in the slice and `ending_index` is one more than the last position in the slice. Internally, the slice data structure stores the starting position and the length of the slice, which corresponds to `ending_index` minus `starting_index`. So in the case of `let world = &s[6..11];`, `world` would be -a slice that contains a pointer to the 6th byte of `s` with a length value of 5. +a slice that contains a pointer to the 7th byte of `s` with a length value of 5. Figure 4-6 shows this in a diagram. diff --git a/src/doc/book/second-edition/src/ch05-01-defining-structs.md b/src/doc/book/second-edition/src/ch05-01-defining-structs.md index ede28b7e23..f3cc2fbc56 100644 --- a/src/doc/book/second-edition/src/ch05-01-defining-structs.md +++ b/src/doc/book/second-edition/src/ch05-01-defining-structs.md @@ -10,7 +10,7 @@ To define a struct, we enter the keyword `struct` and name the entire struct. A struct’s name should describe the significance of the pieces of data being grouped together. Then, inside curly brackets, we define the names and types of the pieces of data, which we call *fields*. For example, Listing 5-1 shows a -struct that stores information about a user account: +struct that stores information about a user account. ```rust struct User { @@ -31,7 +31,7 @@ data we want to store in those fields. We don’t have to specify the fields in the same order in which we declared them in the struct. In other words, the struct definition is like a general template for the type, and instances fill in that template with particular data to create values of the type. For -example, we can declare a particular user as shown in Listing 5-2: +example, we can declare a particular user as shown in Listing 5-2. ```rust # struct User { @@ -56,7 +56,7 @@ To get a specific value from a struct, we can use dot notation. If we wanted just this user’s email address, we could use `user1.email` wherever we wanted to use this value. If the instance is mutable, we can change a value by using the dot notation and assigning into a particular field. Listing 5-3 shows how -to change the value in the `email` field of a mutable `User` instance: +to change the value in the `email` field of a mutable `User` instance. ```rust # struct User { @@ -80,10 +80,10 @@ user1.email = String::from("anotheremail@example.com"); `User` instance Note that the entire instance must be mutable; Rust doesn’t allow us to mark -only certain fields as mutable. +only certain fields as mutable. As with any expression, we can construct a new +instance of the struct as the last expression in the function body to +implicitly return that new instance. -As with any expression, we can construct a new instance of the struct as the -last expression in the function body to implicitly return that new instance. Listing 5-4 shows a `build_user` function that returns a `User` instance with the given email and username. The `active` field gets the value of `true`, and the `sign_in_count` gets a value of `1`. @@ -119,7 +119,7 @@ would get even more annoying. Luckily, there’s a convenient shorthand! Because the parameter names and the struct field names are exactly the same in Listing 5-4, we can use the *field init shorthand* syntax to rewrite `build_user` so that it behaves exactly the same but doesn’t have the -repetition of `email` and `username` as shown in Listing 5-5. +repetition of `email` and `username`, as shown in Listing 5-5. ```rust # struct User { @@ -156,7 +156,7 @@ instance’s values but changes some. You’ll do this using *struct update synt First, Listing 5-6 shows how we create a new `User` instance in `user2` without the update syntax. We set new values for `email` and `username` but otherwise -use the same values from `user1` that we created in Listing 5-2: +use the same values from `user1` that we created in Listing 5-2. ```rust # struct User { @@ -218,7 +218,7 @@ The code in Listing 5-7 also creates an instance in `user2` that has a different value for `email` and `username` but has the same values for the `active` and `sign_in_count` fields from `user1`. -### Tuple Structs without Named Fields to Create Different Types +### Using Tuple Structs without Named Fields to Create Different Types You can also define structs that look similar to tuples, called *tuple structs*. Tuple structs have the added meaning the struct name provides but @@ -227,7 +227,7 @@ of the fields. Tuple structs are useful when you want to give the whole tuple a name and make the tuple be a different type than other tuples, and naming each field as in a regular struct would be verbose or redundant. -To define a tuple struct start with the `struct` keyword and the struct name +To define a tuple struct, start with the `struct` keyword and the struct name followed by the types in the tuple. For example, here are definitions and usages of two tuple structs named `Color` and `Point`: diff --git a/src/doc/book/second-edition/src/ch05-02-example-structs.md b/src/doc/book/second-edition/src/ch05-02-example-structs.md index c59aa42798..457d13e656 100644 --- a/src/doc/book/second-edition/src/ch05-02-example-structs.md +++ b/src/doc/book/second-edition/src/ch05-02-example-structs.md @@ -7,7 +7,7 @@ refactor the program until we’re using structs instead. Let’s make a new binary project with Cargo called *rectangles* that will take the width and height of a rectangle specified in pixels and calculate the area of the rectangle. Listing 5-8 shows a short program with one way of doing -exactly that in our project’s *src/main.rs*: +exactly that in our project’s *src/main.rs*. Filename: src/main.rs @@ -55,7 +55,7 @@ we might do that in “The Tuple Type” section of Chapter 3: by using tuples. ### Refactoring with Tuples -Listing 5-9 shows another version of our program that uses tuples: +Listing 5-9 shows another version of our program that uses tuples. Filename: src/main.rs @@ -94,7 +94,7 @@ our code. We use structs to add meaning by labeling the data. We can transform the tuple we’re using into a data type with a name for the whole as well as names for the -parts, as shown in Listing 5-10: +parts, as shown in Listing 5-10. Filename: src/main.rs @@ -144,7 +144,7 @@ and `1`. This is a win for clarity. It’d be nice to be able to print an instance of `Rectangle` while we’re debugging our program and see the values for all its fields. Listing 5-11 tries using the `println!` macro as we have used in previous chapters. This won’t -work, however: +work, however. Filename: src/main.rs @@ -170,7 +170,7 @@ When we run this code, we get an error with this core message: error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied ``` -The `println!` macro can do many kinds of formatting, and by default, curly +The `println!` macro can do many kinds of formatting, and by default, the curly brackets tell `println!` to use formatting known as `Display`: output intended for direct end user consumption. The primitive types we’ve seen so far implement `Display` by default, because there’s only one way you’d want to show @@ -190,9 +190,9 @@ If we continue reading the errors, we’ll find this helpful note: Let’s try it! The `println!` macro call will now look like `println!("rect1 is {:?}", rect1);`. Putting the specifier `:?` inside the curly brackets tells -`println!` we want to use an output format called `Debug`. `Debug` is a trait -that enables us to print our struct in a way that is useful for developers so -we can see its value while we’re debugging our code. +`println!` we want to use an output format called `Debug`. The `Debug` trait +enables us to print our struct in a way that is useful for developers so we can +see its value while we’re debugging our code. Run the code with this change. Drat! We still get an error: @@ -210,7 +210,7 @@ crate, add `#[derive(Debug)]` or manually implement it Rust *does* include functionality to print out debugging information, but we have to explicitly opt in to make that functionality available for our struct. To do that, we add the annotation `#[derive(Debug)]` just before the struct -definition, as shown in Listing 5-12: +definition, as shown in Listing 5-12. Filename: src/main.rs @@ -253,9 +253,8 @@ rect1 is Rectangle { Rust has provided a number of traits for us to use with the `derive` annotation that can add useful behavior to our custom types. Those traits and their -behaviors are listed in Appendix C, “Derivable Traits.” We’ll cover how to -implement these traits with custom behavior as well as how to create your own -traits in Chapter 10. +behaviors are listed in Appendix C. We’ll cover how to implement these traits +with custom behavior as well as how to create your own traits in Chapter 10. Our `area` function is very specific: it only computes the area of rectangles. It would be helpful to tie this behavior more closely to our `Rectangle` diff --git a/src/doc/book/second-edition/src/ch05-03-method-syntax.md b/src/doc/book/second-edition/src/ch05-03-method-syntax.md index 0a3f0e1077..d8a338c9b6 100644 --- a/src/doc/book/second-edition/src/ch05-03-method-syntax.md +++ b/src/doc/book/second-edition/src/ch05-03-method-syntax.md @@ -12,7 +12,7 @@ instance of the struct the method is being called on. Let’s change the `area` function that has a `Rectangle` instance as a parameter and instead make an `area` method defined on the `Rectangle` struct, as shown -in Listing 5-13: +in Listing 5-13. Filename: src/main.rs @@ -125,7 +125,7 @@ struct. This time, we want an instance of `Rectangle` to take another instance of `Rectangle` and return `true` if the second `Rectangle` can fit completely within `self`; otherwise it should return `false`. That is, we want to be able to write the program shown in Listing 5-14, once we’ve defined the `can_hold` -method: +method. Filename: src/main.rs @@ -164,7 +164,7 @@ calling the `can_hold` method. The return value of `can_hold` will be a Boolean, and the implementation will check whether the width and height of `self` are both greater than the width and height of the other `Rectangle`, respectively. Let’s add the new `can_hold` method to the `impl` block from -Listing 5-13, shown in Listing 5-15: +Listing 5-13, shown in Listing 5-15. Filename: src/main.rs @@ -234,7 +234,7 @@ namespaces created by modules. We’ll discuss modules in Chapter 7. Each struct is allowed to have multiple `impl` blocks. For example, Listing 5-15 is equivalent to the code shown in Listing 5-16, which has each method -in its own `impl` block: +in its own `impl` block. ```rust # #[derive(Debug)] @@ -261,7 +261,7 @@ blocks There’s no reason to separate these methods into multiple `impl` blocks here, but this is valid syntax. We’ll see a case in which multiple `impl` blocks are -useful in Chapter 10 where we discuss generic types and traits. +useful in Chapter 10, where we discuss generic types and traits. ## Summary diff --git a/src/doc/book/second-edition/src/ch06-01-defining-an-enum.md b/src/doc/book/second-edition/src/ch06-01-defining-an-enum.md index e51e76d14d..10898d3aca 100644 --- a/src/doc/book/second-edition/src/ch06-01-defining-an-enum.md +++ b/src/doc/book/second-edition/src/ch06-01-defining-an-enum.md @@ -73,7 +73,7 @@ route(IpAddrKind::V6); Using enums has even more advantages. Thinking more about our IP address type, at the moment we don’t have a way to store the actual IP address *data*; we only know what *kind* it is. Given that you just learned about structs in -Chapter 5, you might tackle this problem as shown in Listing 6-1: +Chapter 5, you might tackle this problem as shown in Listing 6-1. ```rust enum IpAddrKind { @@ -183,7 +183,7 @@ haven’t brought the standard library’s definition into our scope. We’ll ta more about bringing types into scope in Chapter 7. Let’s look at another example of an enum in Listing 6-2: this one has a wide -variety of types embedded in its variants: +variety of types embedded in its variants. ```rust enum Message { @@ -204,7 +204,7 @@ This enum has four variants with different types: * `Write` includes a single `String`. * `ChangeColor` includes three `i32` values. -Defining an enum with variants like the ones in Listing 6-2 is similar to +Defining an enum with variants such as the ones in Listing 6-2 is similar to defining different kinds of struct definitions, except the enum doesn’t use the `struct` keyword and all the variants are grouped together under the `Message` type. The following structs could hold the same data that the preceding enum diff --git a/src/doc/book/second-edition/src/ch06-02-match.md b/src/doc/book/second-edition/src/ch06-02-match.md index 3344b4e5d1..25af009907 100644 --- a/src/doc/book/second-edition/src/ch06-02-match.md +++ b/src/doc/book/second-edition/src/ch06-02-match.md @@ -17,7 +17,7 @@ the value falls into the associated code block to be used during execution. Because we just mentioned coins, let’s use them as an example using `match`! We can write a function that can take an unknown United States coin and, in a similar way as the counting machine, determine which coin it is and return its -value in cents, as shown here in Listing 6-3: +value in cents, as shown here in Listing 6-3. ```rust enum Coin { @@ -100,10 +100,10 @@ From 1999 through 2008, the United States minted quarters with different designs for each of the 50 states on one side. No other coins got state designs, so only quarters have this extra value. We can add this information to our `enum` by changing the `Quarter` variant to include a `UsState` value stored -inside it, which we’ve done here in Listing 6-4: +inside it, which we’ve done here in Listing 6-4. ```rust -#[derive(Debug)] // So we can inspect the state in a minute +#[derive(Debug)] // so we can inspect the state in a minute enum UsState { Alabama, Alaska, @@ -179,7 +179,7 @@ the function should return the `None` value and not attempt to perform any operations. This function is very easy to write, thanks to `match`, and will look like -Listing 6-5: +Listing 6-5. ```rust fn plus_one(x: Option) -> Option { @@ -292,4 +292,4 @@ can say that we want to do nothing for all the possible values that we don’t list before the `_` placeholder. However, the `match` expression can be a bit wordy in a situation in which we -only care about *one* of the cases. For this situation, Rust provides `if let`. +care about only *one* of the cases. For this situation, Rust provides `if let`. diff --git a/src/doc/book/second-edition/src/ch06-03-if-let.md b/src/doc/book/second-edition/src/ch06-03-if-let.md index 033d339388..6583546387 100644 --- a/src/doc/book/second-edition/src/ch06-03-if-let.md +++ b/src/doc/book/second-edition/src/ch06-03-if-let.md @@ -3,7 +3,7 @@ The `if let` syntax lets you combine `if` and `let` into a less verbose way to handle values that match one pattern while ignoring the rest. Consider the program in Listing 6-6 that matches on an `Option` value but only wants to -execute code if the value is 3: +execute code if the value is 3. ```rust let some_u8_value = Some(0u8); @@ -31,15 +31,15 @@ if let Some(3) = some_u8_value { } ``` -The syntax `if let` takes a pattern and an expression separated by an `=`. It -works the same way as a `match`, where the expression is given to the `match` -and the pattern is its first arm. +The syntax `if let` takes a pattern and an expression separated by an equal +sign. It works the same way as a `match`, where the expression is given to the +`match` and the pattern is its first arm. -Using `if let` means you have less typing, less indentation, and less -boilerplate code. However, you lose the exhaustive checking that `match` -enforces. Choosing between `match` and `if let` depends on what you’re doing in -your particular situation and whether gaining conciseness is an appropriate -trade-off for losing exhaustive checking. +Using `if let` means less typing, less indentation, and less boilerplate code. +However, you lose the exhaustive checking that `match` enforces. Choosing +between `match` and `if let` depends on what you’re doing in your particular +situation and whether gaining conciseness is an appropriate trade-off for +losing exhaustive checking. In other words, you can think of `if let` as syntax sugar for a `match` that runs code when the value matches one pattern and then ignores all other values. diff --git a/src/doc/book/second-edition/src/ch07-01-mod-and-the-filesystem.md b/src/doc/book/second-edition/src/ch07-01-mod-and-the-filesystem.md index e5e3718a85..4e2c4ff9a5 100644 --- a/src/doc/book/second-edition/src/ch07-01-mod-and-the-filesystem.md +++ b/src/doc/book/second-edition/src/ch07-01-mod-and-the-filesystem.md @@ -70,7 +70,7 @@ would need to specify the module and use the namespace syntax `::` like so: We can also have multiple modules, side by side, in the same *src/lib.rs* file. For example, to also have a `client` module that has a function named -`connect`, we can add it as shown in Listing 7-1: +`connect`, we can add it as shown in Listing 7-1. Filename: src/lib.rs @@ -103,7 +103,7 @@ related functionality organized together and separate functionality apart. The way you choose to organize your code depends on how you think about the relationship between the parts of your code. For instance, the `client` code and its `connect` function might make more sense to users of our library if -they were inside the `network` namespace instead, as in Listing 7-2: +they were inside the `network` namespace instead, as in Listing 7-2. Filename: src/lib.rs @@ -161,7 +161,7 @@ Modules form a hierarchical structure, much like another structure in computing that you’re used to: filesystems! We can use Rust’s module system along with multiple files to split up Rust projects so not everything lives in *src/lib.rs* or *src/main.rs*. For this example, let’s start with the code in -Listing 7-3: +Listing 7-3. Filename: src/lib.rs @@ -202,7 +202,7 @@ These would be good reasons to separate the `client`, `network`, and `server` modules from *src/lib.rs* and place them into their own files. First, let’s replace the `client` module code with only the declaration of the -`client` module so that *src/lib.rs* looks like code shown in Listing 7-4: +`client` module so that *src/lib.rs* looks like code shown in Listing 7-4. Filename: src/lib.rs @@ -345,7 +345,7 @@ fn connect() { } ``` -When we try to `cargo build`, we’ll get the error shown in Listing 7-5: +When we try to run `cargo build`, we’ll get the error shown in Listing 7-5. ```text $ cargo build @@ -400,7 +400,7 @@ $ mv src/server.rs src/network ``` Now when we try to run `cargo build`, compilation will work (we’ll still have -warnings though). Our module layout still looks exactly the same as it did when +warnings, though). Our module layout still looks exactly the same as it did when we had all the code in *src/lib.rs* in Listing 7-3: ```text diff --git a/src/doc/book/second-edition/src/ch07-02-controlling-visibility-with-pub.md b/src/doc/book/second-edition/src/ch07-02-controlling-visibility-with-pub.md index 4a2df59689..1fef908adb 100644 --- a/src/doc/book/second-edition/src/ch07-02-controlling-visibility-with-pub.md +++ b/src/doc/book/second-edition/src/ch07-02-controlling-visibility-with-pub.md @@ -3,9 +3,9 @@ We resolved the error messages shown in Listing 7-5 by moving the `network` and `network::server` code into the *src/network/mod.rs* and *src/network/server.rs* files, respectively. At that point, `cargo build` was -able to build our project, but we still get warning messages about the +able to build our project, but we still get warning messages saying that the `client::connect`, `network::connect`, and `network::server::connect` functions -not being used. +are not being used. So why are we receiving these warnings? After all, we’re building a library with functions that are intended to be used by our *users*, not necessarily by @@ -14,7 +14,7 @@ functions go unused. The point of creating them is that they will be used by another project, not our own. To understand why this program invokes these warnings, let’s try using the -`connect` library from another project, calling it externally. To do that, +`communicator` library from another project, calling it externally. To do that, we’ll create a binary crate in the same directory as our library crate by making a *src/main.rs* file containing this code: @@ -217,7 +217,7 @@ Overall, these are the rules for item visibility: Let’s look at a few more privacy examples to get some practice. Create a new library project and enter the code in Listing 7-6 into your new project’s -*src/lib.rs*: +*src/lib.rs*. Filename: src/lib.rs @@ -258,8 +258,7 @@ the current (root) module, as is `try_me`. The call to `outermost::middle_function` will work because `middle_function` is public and `try_me` is accessing `middle_function` through its parent module -`outermost`. We determined in the previous paragraph that this module is -accessible. +`outermost`. We already determined that this module is accessible. The call to `outermost::middle_secret_function` will cause a compilation error. Because `middle_secret_function` is private, the second rule applies. The root diff --git a/src/doc/book/second-edition/src/ch07-03-importing-names-with-use.md b/src/doc/book/second-edition/src/ch07-03-importing-names-with-use.md index 4f3d258f07..0af8a736dd 100644 --- a/src/doc/book/second-edition/src/ch07-03-importing-names-with-use.md +++ b/src/doc/book/second-edition/src/ch07-03-importing-names-with-use.md @@ -2,7 +2,7 @@ We’ve covered how to call functions defined within a module using the module name as part of the call, as in the call to the `nested_modules` function shown -here in Listing 7-7: +here in Listing 7-7. Filename: src/main.rs @@ -126,9 +126,10 @@ fn main() { } ``` -The `*` will bring into scope all the visible items in the `TrafficLight` -namespace. You should use globs sparingly: they are convenient, but a glob -might also pull in more items than you expected and cause naming conflicts. +The `*` operator will bring into scope all the visible items in the +`TrafficLight` namespace. You should use globs sparingly: they are convenient, +but a glob might also pull in more items than you expected and cause naming +conflicts. ### Using `super` to Access a Parent Module diff --git a/src/doc/book/second-edition/src/ch08-01-vectors.md b/src/doc/book/second-edition/src/ch08-01-vectors.md index 6452b42a82..889fc4868f 100644 --- a/src/doc/book/second-edition/src/ch08-01-vectors.md +++ b/src/doc/book/second-edition/src/ch08-01-vectors.md @@ -9,7 +9,7 @@ lines of text in a file or the prices of items in a shopping cart. ### Creating a New Vector To create a new, empty vector, we can call the `Vec::new` function, as shown in -Listing 8-1: +Listing 8-1. ```rust let v: Vec = Vec::new(); @@ -32,7 +32,7 @@ store once you insert values, so you rarely need to do this type annotation. It’s more common to create a `Vec` that has initial values, and Rust provides the `vec!` macro for convenience. The macro will create a new vector that holds the values you give it. Listing 8-2 creates a new `Vec` that -holds the values `1`, `2`, and `3`: +holds the values `1`, `2`, and `3`. ```rust let v = vec![1, 2, 3]; @@ -48,7 +48,7 @@ to modify a vector. ### Updating a Vector To create a vector and then add elements to it, we can use the `push` method, -as shown in Listing 8-3: +as shown in Listing 8-3. ```rust let mut v = Vec::new(); @@ -70,7 +70,7 @@ we don’t need the `Vec` annotation. ### Dropping a Vector Drops Its Elements Like any other `struct`, a vector is freed when it goes out of scope, as -annotated in Listing 8-4: +annotated in Listing 8-4. ```rust { @@ -97,7 +97,7 @@ value stored in a vector. In the examples, we’ve annotated the types of the values that are returned from these functions for extra clarity. Listing 8-5 shows both methods of accessing a value in a vector, either with -indexing syntax or the `get` method: +indexing syntax or the `get` method. ```rust let v = vec![1, 2, 3, 4, 5]; @@ -119,7 +119,7 @@ Rust has two ways to reference an element so you can choose how the program behaves when you try to use an index value that the vector doesn’t have an element for. As an example, let’s see what a program will do if it has a vector that holds five elements and then tries to access an element at index 100, as -shown in Listing 8-6: +shown in Listing 8-6. ```rust,should_panic let v = vec![1, 2, 3, 4, 5]; @@ -152,7 +152,7 @@ and any other references to the contents of the vector remain valid. Recall the rule that states you can’t have mutable and immutable references in the same scope. That rule applies in Listing 8-7, where we hold an immutable reference to the first element in a vector and try to add an element to the end, which won’t -work: +work. ```rust,ignore let mut v = vec![1, 2, 3, 4, 5]; @@ -198,7 +198,7 @@ programs from ending up in that situation. If we want to access each element in a vector in turn, we can iterate through all of the elements rather than use indexes to access one at a time. Listing 8-8 shows how to use a `for` loop to get immutable references to each element -in a vector of `i32` values and print them: +in a vector of `i32` values and print them. ```rust let v = vec![100, 32, 57]; @@ -212,7 +212,7 @@ iterating over the elements using a `for` loop We can also iterate over mutable references to each element in a mutable vector in order to make changes to all the elements. The `for` loop in Listing 8-9 -will add `50` to each element: +will add `50` to each element. ```rust let mut v = vec![100, 32, 57]; @@ -241,7 +241,7 @@ some of the columns in the row contain integers, some floating-point numbers, and some strings. We can define an enum whose variants will hold the different value types, and then all the enum variants will be considered the same type: that of the enum. Then we can create a vector that holds that enum and so, -ultimately, holds different types. We’ve demonstrated this in Listing 8-10: +ultimately, holds different types. We’ve demonstrated this in Listing 8-10. ```rust enum SpreadsheetCell { diff --git a/src/doc/book/second-edition/src/ch08-02-strings.md b/src/doc/book/second-edition/src/ch08-02-strings.md index 8473a59b56..7f8eaa8483 100644 --- a/src/doc/book/second-edition/src/ch08-02-strings.md +++ b/src/doc/book/second-edition/src/ch08-02-strings.md @@ -1,7 +1,7 @@ ## Storing UTF-8 Encoded Text with Strings We talked about strings in Chapter 4, but we’ll look at them in more depth now. -New Rustaceans commonly get stuck on strings due to a combination of three +New Rustaceans commonly get stuck on strings for a combination of three reasons: Rust’s propensity for exposing possible errors, strings being a more complicated data structure than many programmers give them credit for, and UTF-8. These factors combine in a way that can seem difficult when you’re @@ -45,7 +45,7 @@ API documentation for more about how to use them and when each is appropriate. Many of the same operations available with `Vec` are available with `String` as well, starting with the `new` function to create a string, shown in Listing -8-11: +8-11. ```rust let mut s = String::new(); @@ -57,7 +57,7 @@ This line creates a new empty string called `s`, which we can then load data into. Often, we’ll have some initial data that we want to start the string with. For that, we use the `to_string` method, which is available on any type that implements the `Display` trait, as string literals do. Listing 8-12 shows -two examples: +two examples. ```rust let data = "initial contents"; @@ -75,7 +75,7 @@ This code creates a string containing `initial contents`. We can also use the function `String::from` to create a `String` from a string literal. The code in Listing 8-13 is equivalent to the code from Listing 8-12 -that uses `to_string`: +that uses `to_string`. ```rust let s = String::from("initial contents"); @@ -90,7 +90,7 @@ redundant, but they all have their place! In this case, `String::from` and `to_string` do the same thing, so which you choose is a matter of style. Remember that strings are UTF-8 encoded, so we can include any properly encoded -data in them, as shown in Listing 8-14: +data in them, as shown in Listing 8-14. ```rust let hello = String::from("السلام عليكم"); @@ -120,7 +120,7 @@ use the `+` operator or the `format!` macro to concatenate `String` values. #### Appending to a String with `push_str` and `push` We can grow a `String` by using the `push_str` method to append a string slice, -as shown in Listing 8-15: +as shown in Listing 8-15. ```rust let mut s = String::from("foo"); @@ -133,7 +133,7 @@ using the `push_str` method After these two lines, `s` will contain `foobar`. The `push_str` method takes a string slice because we don’t necessarily want to take ownership of the parameter. For example, the code in Listing 8-16 shows that it would be -unfortunate if we weren’t able to use `s2` after appending its contents to `s1`: +unfortunate if we weren’t able to use `s2` after appending its contents to `s1`. ```rust let mut s1 = String::from("foo"); @@ -149,8 +149,8 @@ If the `push_str` method took ownership of `s2`, we wouldn’t be able to print its value on the last line. However, this code works as we’d expect! The `push` method takes a single character as a parameter and adds it to the -`String`. Listing 8-17 shows code that adds the letter l to a `String` using -the `push` method: +`String`. Listing 8-17 shows code that adds the letter *l* to a `String` using +the `push` method. ```rust let mut s = String::from("lo"); @@ -165,12 +165,12 @@ As a result of this code, `s` will contain `lol`. #### Concatenation with the `+` Operator or the `format!` Macro Often, you’ll want to combine two existing strings. One way is to use the `+` -operator, as shown in Listing 8-18: +operator, as shown in Listing 8-18. ```rust let s1 = String::from("Hello, "); let s2 = String::from("world!"); -let s3 = s1 + &s2; // Note s1 has been moved here and can no longer be used +let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used ``` Listing 8-18: Using the `+` operator to combine two @@ -248,7 +248,7 @@ easier to read and doesn’t take ownership of any of its parameters. In many other programming languages, accessing individual characters in a string by referencing them by index is a valid and common operation. However, if you try to access parts of a `String` using indexing syntax in Rust, you’ll -get an error. Consider the invalid code in Listing 8-19: +get an error. Consider the invalid code in Listing 8-19. ```rust,ignore let s1 = String::from("hello"); @@ -285,7 +285,7 @@ let len = String::from("Hola").len(); In this case, `len` will be 4, which means the vector storing the string “Hola” is 4 bytes long. Each of these letters takes 1 byte when encoded in UTF-8. But -what about the following line? (Note that this line begins with the capital +what about the following line? (Note that this string begins with the capital Cyrillic letter Ze, not the Arabic number 3.) ```rust @@ -393,7 +393,7 @@ Fortunately, you can access elements in a string in other ways. If you need to perform operations on individual Unicode scalar values, the best way to do so is to use the `chars` method. Calling `chars` on “नमस्ते” separates out and returns six values of type `char`, and you can iterate over the result -in order to access each element: +to access each element: ```rust for c in "नमस्ते".chars() { diff --git a/src/doc/book/second-edition/src/ch08-03-hash-maps.md b/src/doc/book/second-edition/src/ch08-03-hash-maps.md index ecf147eda6..a081a7d43c 100644 --- a/src/doc/book/second-edition/src/ch08-03-hash-maps.md +++ b/src/doc/book/second-edition/src/ch08-03-hash-maps.md @@ -22,7 +22,7 @@ As always, check the standard library documentation for more information. You can create an empty hash map with `new` and add elements with `insert`. In Listing 8-20, we’re keeping track of the scores of two teams whose names are Blue and Yellow. The Blue team starts with 10 points, and the Yellow team -starts with 50: +starts with 50. ```rust use std::collections::HashMap; @@ -53,7 +53,7 @@ vector of tuples, where each tuple consists of a key and its value. The `HashMap`. For example, if we had the team names and initial scores in two separate vectors, we could use the `zip` method to create a vector of tuples where “Blue” is paired with 10, and so forth. Then we could use the `collect` -method to turn that vector of tuples into a hash map, as shown in Listing 8-21: +method to turn that vector of tuples into a hash map, as shown in Listing 8-21. ```rust use std::collections::HashMap; @@ -77,7 +77,7 @@ contains based on the types of the data in the vectors. For types that implement the `Copy` trait, like `i32`, the values are copied into the hash map. For owned values like `String`, the values will be moved and -the hash map will be the owner of those values, as demonstrated in Listing 8-22: +the hash map will be the owner of those values, as demonstrated in Listing 8-22. ```rust use std::collections::HashMap; @@ -105,7 +105,7 @@ the “Validating References with Lifetimes” section in Chapter 10. ### Accessing Values in a Hash Map We can get a value out of the hash map by providing its key to the `get` -method, as shown in Listing 8-23: +method, as shown in Listing 8-23. ```rust use std::collections::HashMap; @@ -168,7 +168,7 @@ If we insert a key and a value into a hash map and then insert that same key with a different value, the value associated with that key will be replaced. Even though the code in Listing 8-24 calls `insert` twice, the hash map will only contain one key/value pair because we’re inserting the value for the Blue -team’s key both times: +team’s key both times. ```rust use std::collections::HashMap; @@ -192,11 +192,11 @@ overwritten. It’s common to check whether a particular key has a value and, if it doesn’t, insert a value for it. Hash maps have a special API for this called `entry` that takes the key you want to check as a parameter. The return value of the -`entry` function is an enum called `Entry` that represents a value that might -or might not exist. Let’s say we want to check whether the key for the Yellow -team has a value associated with it. If it doesn’t, we want to insert the value -50, and the same for the Blue team. Using the `entry` API, the code looks like -Listing 8-25: +`entry` method is an enum called `Entry` that represents a value that might or +might not exist. Let’s say we want to check whether the key for the Yellow team +has a value associated with it. If it doesn’t, we want to insert the value 50, +and the same for the Blue team. Using the `entry` API, the code looks like +Listing 8-25. ```rust use std::collections::HashMap; @@ -221,9 +221,9 @@ logic ourselves and, in addition, plays more nicely with the borrow checker. Running the code in Listing 8-25 will print `{"Yellow": 50, "Blue": 10}`. The first call to `entry` will insert the key for the Yellow team with the value -`50` because the Yellow team doesn’t have a value already. The second call to +50 because the Yellow team doesn’t have a value already. The second call to `entry` will not change the hash map because the Blue team already has the -value `10`. +value 10. #### Updating a Value Based on the Old Value @@ -232,7 +232,7 @@ update it based on the old value. For instance, Listing 8-26 shows code that counts how many times each word appears in some text. We use a hash map with the words as keys and increment the value to keep track of how many times we’ve seen that word. If it’s the first time we’ve seen a word, we’ll first insert -the value `0`: +the value 0. ```rust use std::collections::HashMap; diff --git a/src/doc/book/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md b/src/doc/book/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md index 26cb53dfc9..90103a074c 100644 --- a/src/doc/book/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/src/doc/book/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md @@ -45,10 +45,10 @@ thread 'main' panicked at 'crash and burn', src/main.rs:2:4 note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -The call to `panic!` causes the error message contained in the last three -lines. The first line shows our panic message and the place in our source code -where the panic occurred: *src/main.rs:2:4* indicates that it’s the second -line, fourth character of our *src/main.rs* file. +The call to `panic!` causes the error message contained in the last two lines. +The first line shows our panic message and the place in our source code where +the panic occurred: *src/main.rs:2:4* indicates that it’s the second line, +fourth character of our *src/main.rs* file. In this case, the line indicated is part of our code, and if we go to that line, we see the `panic!` macro call. In other cases, the `panic!` call might @@ -64,7 +64,7 @@ backtrace is in more detail next. Let’s look at another example to see what it’s like when a `panic!` call comes from a library because of a bug in our code instead of from our code calling the macro directly. Listing 9-1 has some code that attempts to access an -element by index in a vector: +element by index in a vector. Filename: src/main.rs @@ -77,13 +77,13 @@ fn main() { ``` Listing 9-1: Attempting to access an element beyond the -end of a vector, which will cause a `panic!` +end of a vector, which will cause a call to `panic!` -Here, we’re attempting to access the hundredth element of our vector (which is -at index 99 because indexing starts at zero), but it has only three elements. -In this situation, Rust will panic. Using `[]` is supposed to return an -element, but if you pass an invalid index, there’s no element that Rust could -return here that would be correct. +Here, we’re attempting to access the 100th element of our vector (which is at +index 99 because indexing starts at zero), but it has only 3 elements. In this +situation, Rust will panic. Using `[]` is supposed to return an element, but if +you pass an invalid index, there’s no element that Rust could return here that +would be correct. Other languages, like C, will attempt to give you exactly what you asked for in this situation, even though it isn’t what you want: you’ll get whatever is at @@ -122,7 +122,7 @@ mentioning your files are code that your code called; the lines below are code that called your code. These lines might include core Rust code, standard library code, or crates that you’re using. Let’s try getting a backtrace by setting the `RUST_BACKTRACE` environment variable to any value except 0. -Listing 9-2 shows output similar to what you’ll see: +Listing 9-2 shows output similar to what you’ll see. ```text $ RUST_BACKTRACE=1 cargo run diff --git a/src/doc/book/second-edition/src/ch09-02-recoverable-errors-with-result.md b/src/doc/book/second-edition/src/ch09-02-recoverable-errors-with-result.md index 9398b2787a..b09bf71052 100644 --- a/src/doc/book/second-edition/src/ch09-02-recoverable-errors-with-result.md +++ b/src/doc/book/second-edition/src/ch09-02-recoverable-errors-with-result.md @@ -29,7 +29,7 @@ library has defined on it in many different situations where the successful value and error value we want to return may differ. Let’s call a function that returns a `Result` value because the function could -fail. In Listing 9-3 we try to open a file: +fail. In Listing 9-3 we try to open a file. Filename: src/main.rs @@ -141,7 +141,7 @@ if `File::open` failed because the file doesn’t exist, we want to create the file and return the handle to the new file. If `File::open` failed for any other reason—for example, because we didn’t have permission to open the file—we still want the code to `panic!` in the same way as it did in Listing 9-4. Look -at Listing 9-5, which adds another arm to the `match`: +at Listing 9-5, which adds another arm to the `match`. Filename: src/main.rs @@ -202,7 +202,7 @@ but `ref` matches a value and gives you a reference to it. The condition we want to check in the match guard is whether the value returned by `error.kind()` is the `NotFound` variant of the `ErrorKind` enum. If it is, we try to create the file with `File::create`. However, because `File::create` -could also fail, we need to add an inner `match` statement as well. When the +could also fail, we need to add an inner `match` expression as well. When the file can’t be opened, a different error message will be printed. The last arm of the outer `match` stays the same so the program panics on any error besides the missing file error. @@ -212,8 +212,8 @@ the missing file error. Using `match` works well enough, but it can be a bit verbose and doesn’t always communicate intent well. The `Result` type has many helper methods defined on it to do various tasks. One of those methods, called `unwrap`, is a -shortcut method that is implemented just like the `match` statement we wrote in -Listing 9-4. If the `Result` value is the `Ok` variant, `unwrap` will return +shortcut method that is implemented just like the `match` expression we wrote +in Listing 9-4. If the `Result` value is the `Ok` variant, `unwrap` will return the value inside the `Ok`. If the `Result` is the `Err` variant, `unwrap` will call the `panic!` macro for us. Here is an example of `unwrap` in action: @@ -278,7 +278,7 @@ handled than what you have available in the context of your code. For example, Listing 9-6 shows a function that reads a username from a file. If the file doesn’t exist or can’t be read, this function will return those errors -to the code that called this function: +to the code that called this function. Filename: src/main.rs @@ -307,19 +307,19 @@ fn read_username_from_file() -> Result { Listing 9-6: A function that returns errors to the calling code using `match` -Let’s look at the return type of the function first: `Result`. This means the function is returning a value of the type -`Result` where the generic parameter `T` has been filled in with the -concrete type `String`, and the generic type `E` has been filled in with the -concrete type `io::Error`. If this function succeeds without any problems, the -code that calls this function will receive an `Ok` value that holds a -`String`—the username that this function read from the file. If this function -encounters any problems, the code that calls this function will receive an -`Err` value that holds an instance of `io::Error` that contains more -information about what the problems were. We chose `io::Error` as the return -type of this function because that happens to be the type of the error value -returned from both of the operations we’re calling in this function’s body that -might fail: the `File::open` function and the `read_to_string` method. +Look at the return type of the function first: `Result`. +This means the function is returning a value of the type `Result` where +the generic parameter `T` has been filled in with the concrete type `String` +and the generic type `E` has been filled in with the concrete type `io::Error`. +If this function succeeds without any problems, the code that calls this +function will receive an `Ok` value that holds a `String`—the username that +this function read from the file. If this function encounters any problems, the +code that calls this function will receive an `Err` value that holds an +instance of `io::Error` that contains more information about what the problems +were. We chose `io::Error` as the return type of this function because that +happens to be the type of the error value returned from both of the operations +we’re calling in this function’s body that might fail: the `File::open` +function and the `read_to_string` method. The body of the function starts by calling the `File::open` function. Then we handle the `Result` value returned with a `match` similar to the `match` in @@ -355,7 +355,7 @@ question mark operator `?` to make this easier. Listing 9-7 shows an implementation of `read_username_from_file` that has the same functionality as it had in Listing 9-6, but this implementation uses the -question mark operator: +`?` operator. Filename: src/main.rs @@ -373,7 +373,7 @@ fn read_username_from_file() -> Result { ``` Listing 9-7: A function that returns errors to the -calling code using `?` +calling code using the `?` operator The `?` placed after a `Result` value is defined to work in almost the same way as the `match` expressions we defined to handle the `Result` values in Listing @@ -384,25 +384,25 @@ function as if we had used the `return` keyword so the error value gets propagated to the calling code. There is a difference between what the `match` expression from Listing 9-6 and -`?` do: error values used with `?` go through the `from` function, defined in -the `From` trait in the standard library, which is used to convert errors from -one type into another. When `?` calls the `from` function, the error type -received is converted into the error type defined in the return type of the -current function. This is useful when a function returns one error type to -represent all the ways a function might fail, even if parts might fail for many -different reasons. As long as each error type implements the `from` function to -define how to convert itself to the returned error type, `?` takes care of the -conversion automatically. +the `?` operator do: error values used with `?` go through the `from` function, +defined in the `From` trait in the standard library, which is used to convert +errors from one type into another. When the `?` operator calls the `from` +function, the error type received is converted into the error type defined in +the return type of the current function. This is useful when a function returns +one error type to represent all the ways a function might fail, even if parts +might fail for many different reasons. As long as each error type implements +the `from` function to define how to convert itself to the returned error type, +the `?` operator takes care of the conversion automatically. In the context of Listing 9-7, the `?` at the end of the `File::open` call will -return the value inside an `Ok` to the variable `f`. If an error occurs, `?` -will return early out of the whole function and give any `Err` value to the -calling code. The same thing applies to the `?` at the end of the +return the value inside an `Ok` to the variable `f`. If an error occurs, the +`?` operator will return early out of the whole function and give any `Err` +value to the calling code. The same thing applies to the `?` at the end of the `read_to_string` call. The `?` operator eliminates a lot of boilerplate and makes this function’s implementation simpler. We could even shorten this code further by chaining -method calls immediately after the `?`, as shown in Listing 9-8: +method calls immediately after the `?`, as shown in Listing 9-8. Filename: src/main.rs @@ -420,7 +420,8 @@ fn read_username_from_file() -> Result { } ``` -Listing 9-8: Chaining method calls after `?` +Listing 9-8: Chaining method calls after the `?` +operator We’ve moved the creation of the new `String` in `s` to the beginning of the function; that part hasn’t changed. Instead of creating a variable `f`, we’ve @@ -439,8 +440,8 @@ expression we defined in Listing 9-6. The part of the `match` that requires a return type of `Result` is `return Err(e)`, so the return type of the function must be a `Result` to be compatible with this `return`. -Let’s look at what happens if we use `?` in the `main` function, which you’ll -recall has a return type of `()`: +Let’s look at what happens if we use the `?` operator in the `main` function, +which you’ll recall has a return type of `()`: ```rust,ignore use std::fs::File; @@ -467,11 +468,11 @@ error[E0277]: the trait bound `(): std::ops::Try` is not satisfied = note: required by `std::ops::Try::from_error` ``` -This error points out that we’re only allowed to use `?` in a function that -returns `Result`. In functions that don’t return `Result`, when you call other -functions that return `Result`, you’ll need to use a `match` or one of the -`Result` methods to handle the `Result` instead of using `?` to potentially -propagate the error to the calling code. +This error points out that we’re only allowed to use the `?` operator in a +function that returns `Result`. In functions that don’t return `Result`, when +you call other functions that return `Result`, you’ll need to use a `match` or +one of the `Result` methods to handle the `Result` instead of using the `?` +operator to potentially propagate the error to the calling code. Now that we’ve discussed the details of calling `panic!` or returning `Result`, let’s return to the topic of how to decide which is appropriate to use in which diff --git a/src/doc/book/second-edition/src/ch09-03-to-panic-or-not-to-panic.md b/src/doc/book/second-edition/src/ch09-03-to-panic-or-not-to-panic.md index 0563684b57..dcf31a64b5 100644 --- a/src/doc/book/second-edition/src/ch09-03-to-panic-or-not-to-panic.md +++ b/src/doc/book/second-edition/src/ch09-03-to-panic-or-not-to-panic.md @@ -118,6 +118,8 @@ even compile, so your function doesn’t have to check for that case at runtime. Another example is using an unsigned integer type such as `u32`, which ensures the parameter is never negative. +### Creating Custom Types for Validation + Let’s take the idea of using Rust’s type system to ensure we have a valid value one step further and look at creating a custom type for validation. Recall the guessing game in Chapter 2 in which our code asked the user to guess a number @@ -168,7 +170,7 @@ an instance of the type rather than repeating the validations everywhere. That way, it’s safe for functions to use the new type in their signatures and confidently use the values they receive. Listing 9-9 shows one way to define a `Guess` type that will only create an instance of `Guess` if the `new` function -receives a value between 1 and 100: +receives a value between 1 and 100. ```rust pub struct Guess { @@ -240,4 +242,3 @@ situations will make your code more reliable in the face of inevitable problems. Now that you’ve seen useful ways that the standard library uses generics with the `Option` and `Result` enums, we’ll talk about how generics work and how you can use them in your code. - diff --git a/src/doc/book/second-edition/src/ch10-00-generics.md b/src/doc/book/second-edition/src/ch10-00-generics.md index 13c7353efd..3c52723224 100644 --- a/src/doc/book/second-edition/src/ch10-00-generics.md +++ b/src/doc/book/second-edition/src/ch10-00-generics.md @@ -65,7 +65,7 @@ the first number in the list in a variable named `largest`. Then it iterates through all the numbers in the list, and if the current number is greater than the number stored in `largest`, it replaces the number in that variable. However, if the current number is less than the largest number seen so far, the -variable doesn’t change and the code moves on to the next number in the list. +variable doesn’t change, and the code moves on to the next number in the list. After considering all the numbers in the list, `largest` should hold the largest number, which in this case is 100. @@ -161,7 +161,7 @@ In sum, here are the steps we took to change the code from Listing 10-2 to Listing 10-3: 1. Identify duplicate code. -2. Extract the duplicate code into the body of the function, and specify the +2. Extract the duplicate code into the body of the function and specify the inputs and return values of that code in the function signature. 3. Update the two instances of duplicated code to call the function instead. diff --git a/src/doc/book/second-edition/src/ch10-01-syntax.md b/src/doc/book/second-edition/src/ch10-01-syntax.md index 3bba4a6d73..9c8fd4fcbf 100644 --- a/src/doc/book/second-edition/src/ch10-01-syntax.md +++ b/src/doc/book/second-edition/src/ch10-01-syntax.md @@ -194,11 +194,11 @@ fn main() { ``` Listing 10-7: The fields `x` and `y` must be the same -type because both have the same generic data type `T` +type because both have the same generic data type `T`. -In this example, when we assign the integer value `5` to `x`, we let the +In this example, when we assign the integer value 5 to `x`, we let the compiler know that the generic type `T` will be an integer for this instance of -`Point`. Then when we specify `4.0` for `y`, which we’ve defined to have the +`Point`. Then when we specify 4.0 for `y`, which we’ve defined to have the same type as `x`, we’ll get a type mismatch error like this: ```text @@ -287,7 +287,7 @@ avoid duplication by using generic types instead. ### In Method Definitions We can implement methods on structs and enums (as we did in Chapter 5) and use -generic types in their definitions too. Listing 10-9 shows the `Point` +generic types in their definitions, too. Listing 10-9 shows the `Point` struct we defined in Listing 10-6 with a method named `x` implemented on it. Filename: src/main.rs @@ -344,7 +344,7 @@ impl Point { struct with a particular concrete type for the generic type parameter `T` This code means the type `Point` will have a method named -`distance_from_origin`, and other instances of `Point` where `T` is not of +`distance_from_origin` and other instances of `Point` where `T` is not of type `f32` will not have this method defined. The method measures how far our point is from the point at coordinates (0.0, 0.0) and uses mathematical operations that are available only for floating point types. @@ -355,7 +355,7 @@ the method `mixup` on the `Point` struct from Listing 10-8. The method takes another `Point` as a parameter, which might have different types than the `self` `Point` we’re calling `mixup` on. The method creates a new `Point` instance with the `x` value from the `self` `Point` (of type `T`) and the `y` -value from the passed-in `Point` (of type `W`): +value from the passed-in `Point` (of type `W`). Filename: src/main.rs diff --git a/src/doc/book/second-edition/src/ch10-02-traits.md b/src/doc/book/second-edition/src/ch10-02-traits.md index 4fc8449fe0..27c7014e18 100644 --- a/src/doc/book/second-edition/src/ch10-02-traits.md +++ b/src/doc/book/second-edition/src/ch10-02-traits.md @@ -332,7 +332,7 @@ error[E0369]: binary operation `>` cannot be applied to type `T` ``` In the body of `largest` we wanted to compare two values of type `T` using the -greater-than (`>`) operator. Because that operator is defined as a default +greater than (`>`) operator. Because that operator is defined as a default method on the standard library trait `std::cmp::PartialOrd`, we need to specify `PartialOrd` in the trait bounds for `T` so the `largest` function can work on slices of any type that we can compare. We don’t need to bring `PartialOrd` diff --git a/src/doc/book/second-edition/src/ch10-03-lifetime-syntax.md b/src/doc/book/second-edition/src/ch10-03-lifetime-syntax.md index b59eb5ef10..6e4a8924f3 100644 --- a/src/doc/book/second-edition/src/ch10-03-lifetime-syntax.md +++ b/src/doc/book/second-edition/src/ch10-03-lifetime-syntax.md @@ -43,11 +43,11 @@ has gone out of scope > without giving them an initial value, so the variable name exists in the > outer scope. At first glance, this might appear to be in conflict with Rust’s > having no null values. However, if we try to use a variable before giving it -> a value, we’ll get a compile time error, which shows that Rust indeed does +> a value, we’ll get a compile-time error, which shows that Rust indeed does > not allow null values. The outer scope declares a variable named `r` with no initial value, and the -inner scope declares a variable named `x` with the initial value of `5`. Inside +inner scope declares a variable named `x` with the initial value of 5. Inside the inner scope, we attempt to set the value of `r` as a reference to `x`. Then the inner scope ends, and we attempt to print the value in `r`. This code won’t compile because the value `r` is referring to has gone out of scope before we @@ -512,8 +512,8 @@ the `ImportantExcerpt` goes out of scope, so the reference in the You’ve learned that every reference has a lifetime and that you need to specify lifetime parameters for functions or structs that use references. However, in -Chapter 4 we had a function in the “String Slices” section, which is shown again -in Listing 10-26, that compiled without lifetime annotations. +Chapter 4 we had a function in Listing 4-9, which is shown again in Listing +10-26, that compiled without lifetime annotations. Filename: src/lib.rs @@ -601,7 +601,8 @@ fn first_word(s: &str) -> &str { ``` Then the compiler applies the first rule, which specifies that each parameter -gets its own lifetime. We’ll call it `'a` as usual, so now the signature is: +gets its own lifetime. We’ll call it `'a` as usual, so now the signature is +this: ```rust,ignore fn first_word<'a>(s: &'a str) -> &str { diff --git a/src/doc/book/second-edition/src/ch11-01-writing-tests.md b/src/doc/book/second-edition/src/ch11-01-writing-tests.md index 8e17bf0c16..411cef772a 100644 --- a/src/doc/book/second-edition/src/ch11-01-writing-tests.md +++ b/src/doc/book/second-edition/src/ch11-01-writing-tests.md @@ -43,7 +43,7 @@ $ cd adder ``` The contents of the *src/lib.rs* file in your `adder` library should look like -Listing 11-1: +Listing 11-1. Filename: src/lib.rs @@ -73,7 +73,7 @@ This assertion serves as an example of the format for a typical test. Let’s ru it to see that this test passes. The `cargo test` command runs all tests in our project, as shown in Listing -11-2: +11-2. ```text $ cargo test @@ -118,8 +118,8 @@ The next part of the test output, which starts with `Doc-tests adder`, is for the results of any documentation tests. We don’t have any documentation tests yet, but Rust can compile any code examples that appear in our API documentation. This feature helps us keep our docs and our code in sync! We’ll -discuss how to write documentation tests in the “Documentation Comments” -section of Chapter 14. For now, we’ll ignore the `Doc-tests` output. +discuss how to write documentation tests in the “Documentation Comments as +Tests” section of Chapter 14. For now, we’ll ignore the `Doc-tests` output. Let’s change the name of our test to see how that changes the test output. Change the `it_works` function to a different name, such as `exploration`, like @@ -153,7 +153,7 @@ when something in the test function panics. Each test is run in a new thread, and when the main thread sees that a test thread has died, the test is marked as failed. We talked about the simplest way to cause a panic in Chapter 9, which is to call the `panic!` macro. Enter the new test, `another`, so your -*src/lib.rs* file looks like Listing 11-3: +*src/lib.rs* file looks like Listing 11-3. Filename: src/lib.rs @@ -177,7 +177,7 @@ mod tests { we call the `panic!` macro Run the tests again using `cargo test`. The output should look like Listing -11-4, which shows that our `exploration` test passed and `another` failed: +11-4, which shows that our `exploration` test passed and `another` failed. ```text running 2 tests @@ -255,7 +255,7 @@ The `can_hold` method returns a Boolean, which means it’s a perfect use case for the `assert!` macro. In Listing 11-6, we write a test that exercises the `can_hold` method by creating a `Rectangle` instance that has a length of 8 and a width of 7 and asserting that it can hold another `Rectangle` instance that -has a length of 5 and a width of 1: +has a length of 5 and a width of 1. Filename: src/lib.rs @@ -337,7 +337,7 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Two tests that pass! Now let’s see what happens to our test results when we introduce a bug in our code. Let’s change the implementation of the `can_hold` -method by replacing the greater-than sign with a less-than sign when it +method by replacing the greater than sign with a less than sign when it compares the lengths: ```rust @@ -496,8 +496,8 @@ those types are equal or not equal. You’ll need to implement `Debug` to print the values when the assertion fails. Because both traits are derivable traits, as mentioned in Listing 5-12 in Chapter 5, this is usually as straightforward as adding the `#[derive(PartialEq, Debug)]` annotation to your struct or enum -definition. See Appendix C, “Derivable Traits,” for more details about these -and other derivable traits. +definition. See Appendix C for more details about these and other derivable +traits. ### Adding Custom Failure Messages @@ -612,7 +612,7 @@ This attribute makes a test pass if the code inside the function panics; the test will fail if the code inside the function doesn’t panic. Listing 11-8 shows a test that checks that the error conditions of `Guess::new` -happen when we expect them to: +happen when we expect them to. Filename: src/lib.rs @@ -709,7 +709,7 @@ make `should_panic` tests more precise, we can add an optional `expected` parameter to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. For example, consider the modified code for `Guess` in Listing 11-9 where the `new` function panics with -different messages depending on whether the value is too small or too large: +different messages depending on whether the value is too small or too large. Filename: src/lib.rs diff --git a/src/doc/book/second-edition/src/ch11-02-running-tests.md b/src/doc/book/second-edition/src/ch11-02-running-tests.md index 8f9155e687..74ca1b69f6 100644 --- a/src/doc/book/second-edition/src/ch11-02-running-tests.md +++ b/src/doc/book/second-edition/src/ch11-02-running-tests.md @@ -157,7 +157,7 @@ that code. You can choose which tests to run by passing `cargo test` the name or names of the test(s) you want to run as an argument. To demonstrate how to run a subset of tests, we’ll create three tests for our -`add_two` function, as shown in Listing 11-11, and choose which ones to run: +`add_two` function, as shown in Listing 11-11, and choose which ones to run. Filename: src/lib.rs diff --git a/src/doc/book/second-edition/src/ch11-03-test-organization.md b/src/doc/book/second-edition/src/ch11-03-test-organization.md index 0d0bad6bbb..a23910d196 100644 --- a/src/doc/book/second-edition/src/ch11-03-test-organization.md +++ b/src/doc/book/second-edition/src/ch11-03-test-organization.md @@ -10,7 +10,7 @@ external code would, using only the public interface and potentially exercising multiple modules per test. Writing both kinds of tests is important to ensure that the pieces of your -library are doing what you expect them to separately and together. +library are doing what you expect them to, separately and together. ### Unit Tests @@ -62,7 +62,7 @@ There’s debate within the testing community about whether or not private functions should be tested directly, and other languages make it difficult or impossible to test private functions. Regardless of which testing ideology you adhere to, Rust’s privacy rules do allow you to test private functions. -Consider the code in Listing 11-12 with the private function `internal_adder`: +Consider the code in Listing 11-12 with the private function `internal_adder`. Filename: src/lib.rs @@ -113,7 +113,7 @@ will compile each of the files as an individual crate. Let’s create an integration test. With the code in Listing 11-12 still in the *src/lib.rs* file, make a *tests* directory, create a new file named -*tests/integration_test.rs*, and enter the code in Listing 11-13: +*tests/integration_test.rs*, and enter the code in Listing 11-13. Filename: tests/integration_test.rs diff --git a/src/doc/book/second-edition/src/ch12-01-accepting-command-line-arguments.md b/src/doc/book/second-edition/src/ch12-01-accepting-command-line-arguments.md index f013eea800..9f84742637 100644 --- a/src/doc/book/second-edition/src/ch12-01-accepting-command-line-arguments.md +++ b/src/doc/book/second-edition/src/ch12-01-accepting-command-line-arguments.md @@ -36,7 +36,7 @@ the `collect` method on an iterator to turn it into a collection, such as a vector, containing all the elements the iterator produces. Use the code in Listing 12-1 to allow your `minigrep` program to read any -command line arguments passed to it and then collect the values into a vector: +command line arguments passed to it and then collect the values into a vector. Filename: src/main.rs @@ -105,7 +105,7 @@ chapter, we’ll ignore it and save only the two arguments we need. Printing the value of the vector of arguments illustrated that the program is able to access the values specified as command line arguments. Now we need to save the values of the two arguments in variables so we can use the values -throughout the rest of the program. We do that in Listing 12-2: +throughout the rest of the program. We do that in Listing 12-2. Filename: src/main.rs diff --git a/src/doc/book/second-edition/src/ch12-02-reading-a-file.md b/src/doc/book/second-edition/src/ch12-02-reading-a-file.md index 9e70465cb2..9aa9b18bf3 100644 --- a/src/doc/book/second-edition/src/ch12-02-reading-a-file.md +++ b/src/doc/book/second-edition/src/ch12-02-reading-a-file.md @@ -11,10 +11,10 @@ Who are you?” Filename: poem.txt ```text -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us — don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog @@ -26,7 +26,7 @@ To an admiring bog! case With the text in place, edit *src/main.rs* and add code to open the file, as -shown in Listing 12-4: +shown in Listing 12-4. Filename: src/main.rs @@ -90,10 +90,10 @@ $ cargo run the poem.txt Searching for the In file poem.txt With text: -I’m nobody! Who are you? +I'm nobody! Who are you? Are you nobody, too? -Then there’s a pair of us — don’t tell! -They’d banish us, you know. +Then there's a pair of us - don't tell! +They'd banish us, you know. How dreary to be somebody! How public, like a frog diff --git a/src/doc/book/second-edition/src/ch12-03-improving-error-handling-and-modularity.md b/src/doc/book/second-edition/src/ch12-03-improving-error-handling-and-modularity.md index 072400699d..7ab8c46f2f 100644 --- a/src/doc/book/second-edition/src/ch12-03-improving-error-handling-and-modularity.md +++ b/src/doc/book/second-edition/src/ch12-03-improving-error-handling-and-modularity.md @@ -49,13 +49,14 @@ process has the following steps: *main.rs*. * When the command line parsing logic starts getting complicated, extract it from *main.rs* and move it to *lib.rs*. -* The responsibilities that remain in the `main` function after this process - should be limited to the following: - * Calling the command line parsing logic with the argument values - * Setting up any other configuration - * Calling a `run` function in *lib.rs* - * Handling the error if `run` returns an error +The responsibilities that remain in the `main` function after this process +should be limited to the following: + +* Calling the command line parsing logic with the argument values +* Setting up any other configuration +* Calling a `run` function in *lib.rs* +* Handling the error if `run` returns an error This pattern is about separating concerns: *main.rs* handles running the program, and *lib.rs* handles all the logic of the task at hand. Because you @@ -94,8 +95,8 @@ fn parse_config(args: &[String]) -> (&str, &str) { `main` We’re still collecting the command line arguments into a vector, but instead of -assigning the argument value at index `1` to the variable `query` and the -argument value at index `2` to the variable `filename` within the `main` +assigning the argument value at index 1 to the variable `query` and the +argument value at index 2 to the variable `filename` within the `main` function, we pass the whole vector to the `parse_config` function. The `parse_config` function then holds the logic that determines which argument goes in which variable and passes the values back to `main`. We still create @@ -127,10 +128,7 @@ other and what their purpose is. > Note: Some people call this anti-pattern of using primitive values when a > complex type would be more appropriate *primitive obsession*. -Listing 12-6 shows the addition of a struct named `Config` defined to have -fields named `query` and `filename`. We’ve also changed the `parse_config` -function to return an instance of the `Config` struct and updated `main` to use -the struct fields rather than having separate variables: +Listing 12-6 shows the improvements to the `parse_config` function. Filename: src/main.rs @@ -167,13 +165,14 @@ fn parse_config(args: &[String]) -> Config { Listing 12-6: Refactoring `parse_config` to return an instance of a `Config` struct -The signature of `parse_config` now indicates that it returns a `Config` value. -In the body of `parse_config`, where we used to return string slices that -reference `String` values in `args`, we now define `Config` to contain owned -`String` values. The `args` variable in `main` is the owner of the argument -values and is only letting the `parse_config` function borrow them, which means -we’d violate Rust’s borrowing rules if `Config` tried to take ownership of the -values in `args`. +We’ve added a struct named `Config` defined to have fields named `query` and +`filename`. The signature of `parse_config` now indicates that it returns a +`Config` value. In the body of `parse_config`, where we used to return string +slices that reference `String` values in `args`, we now define `Config` to +contain owned `String` values. The `args` variable in `main` is the owner of +the argument values and is only letting the `parse_config` function borrow +them, which means we’d violate Rust’s borrowing rules if `Config` tried to take +ownership of the values in `args`. We could manage the `String` data in a number of different ways, but the easiest, though somewhat inefficient, route is to call the `clone` method on @@ -222,7 +221,7 @@ will make the code more idiomatic. We can create instances of types in the standard library, such as `String`, by calling `String::new`. Similarly, by changing `parse_config` into a `new` function associated with `Config`, we’ll be able to create instances of `Config` by calling `Config::new`. Listing 12-7 -shows the changes we need to make: +shows the changes we need to make. Filename: src/main.rs @@ -265,9 +264,9 @@ compiling this code again to make sure it works. ### Fixing the Error Handling Now we’ll work on fixing our error handling. Recall that attempting to access -the values in the `args` vector at index `1` or index `2` will cause the -program to panic if the vector contains fewer than three items. Try running the -program without any arguments; it will look like this: +the values in the `args` vector at index 1 or index 2 will cause the program to +panic if the vector contains fewer than three items. Try running the program +without any arguments; it will look like this: ```text $ cargo run @@ -286,9 +285,9 @@ happened and what they should do instead. Let’s fix that now. #### Improving the Error Message In Listing 12-8, we add a check in the `new` function that will verify that the -slice is long enough before accessing index `1` and `2`. If the slice isn’t -long enough, the program panics and displays a better error message than the -`index out of bounds` message. +slice is long enough before accessing index 1 and 2. If the slice isn’t long +enough, the program panics and displays a better error message than the `index +out of bounds` message. Filename: src/main.rs @@ -304,13 +303,13 @@ fn new(args: &[String]) -> Config { Listing 12-8: Adding a check for the number of arguments -This code is similar to the `Guess::new` function we wrote in Listing 9-9, where -we called `panic!` when the `value` argument was out of the range of valid -values. Instead of checking for a range of values here, we’re checking that the -length of `args` is at least `3` and the rest of the function can operate under -the assumption that this condition has been met. If `args` has fewer than three -items, this condition will be true, and we call the `panic!` macro to end the -program immediately. +This code is similar to the `Guess::new` function we wrote in Listing 9-9, +where we called `panic!` when the `value` argument was out of the range of +valid values. Instead of checking for a range of values here, we’re checking +that the length of `args` is at least 3 and the rest of the function can +operate under the assumption that this condition has been met. If `args` has +fewer than three items, this condition will be true, and we call the `panic!` +macro to end the program immediately. With these extra few lines of code in `new`, let’s run the program without any arguments again to see what the error looks like now: @@ -327,10 +326,10 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. This output is better: we now have a reasonable error message. However, we also have extraneous information we don’t want to give to our users. Perhaps using the technique we used in Listing 9-9 isn’t the best to use here: a call to -`panic!` is more appropriate for a programming problem rather than a usage -problem, as discussed in Chapter 9. Instead, we can use the other technique you -learned about in Chapter 9—returning a `Result` that indicates either success -or an error. +`panic!` is more appropriate for a programming problem than a usage problem, as +discussed in Chapter 9. Instead, we can use the other technique you learned +about in Chapter 9—returning a `Result` that indicates either success or an +error. #### Returning a `Result` from `new` Instead of Calling `panic!` @@ -493,7 +492,7 @@ Instead of allowing the program to panic by calling `expect`, the `run` function will return a `Result` when something goes wrong. This will let us further consolidate into `main` the logic around handling errors in a user-friendly way. Listing 12-12 shows the changes we need to make to the -signature and body of `run`: +signature and body of `run`. Filename: src/main.rs @@ -530,9 +529,9 @@ have to specify what particular type the return value will be. This gives us flexibility to return error values that may be of different types in different error cases. -Second, we’ve removed the calls to `expect` in favor of `?`, as we talked about -in Chapter 9. Rather than `panic!` on an error, `?` will return the error value -from the current function for the caller to handle. +Second, we’ve removed the calls to `expect` in favor of the `?` operator, as we +talked about in Chapter 9. Rather than `panic!` on an error, the `?` operator +will return the error value from the current function for the caller to handle. Third, the `run` function now returns an `Ok` value in the success case. We’ve declared the `run` function’s success type as `()` in the signature, which @@ -555,7 +554,7 @@ warning: unused `std::result::Result` which must be used Rust tells us that our code ignored the `Result` value and the `Result` value might indicate that an error occurred. But we’re not checking to see whether or not there was an error, and the compiler reminds us that we probably meant to -have some error handling code here! Let’s rectify that problem now. +have some error-handling code here! Let’s rectify that problem now. #### Handling Errors Returned from `run` in `main` @@ -605,7 +604,7 @@ Let’s move all the code that isn’t the `main` function from *src/main.rs* to The contents of *src/lib.rs* should have the signatures shown in Listing 12-13 (we’ve omitted the bodies of the functions for brevity). Note that this won’t -compile until we modify *src/main.rs* in the listing after this one. +compile until we modify *src/main.rs* in Listing 12-14. Filename: src/lib.rs @@ -638,7 +637,7 @@ We’ve made liberal use of the `pub` keyword: on `Config`, on its fields and it public API that we can test! Now we need to bring the code we moved to *src/lib.rs* into the scope of the -binary crate in *src/main.rs*, as shown in Listing 12-14: +binary crate in *src/main.rs*, as shown in Listing 12-14. Filename: src/main.rs diff --git a/src/doc/book/second-edition/src/ch12-04-testing-the-librarys-functionality.md b/src/doc/book/second-edition/src/ch12-04-testing-the-librarys-functionality.md index 7bd761bc54..cb0a892ea9 100644 --- a/src/doc/book/second-edition/src/ch12-04-testing-the-librarys-functionality.md +++ b/src/doc/book/second-edition/src/ch12-04-testing-the-librarys-functionality.md @@ -35,7 +35,7 @@ Then, in *src/lib.rs*, we’ll add a `test` module with a test function, as we did in Chapter 11. The test function specifies the behavior we want the `search` function to have: it will take a query and the text to search for the query in, and it will return only the lines from the text that contain the -query. Listing 12-15 shows this test, which won’t compile yet: +query. Listing 12-15 shows this test, which won’t compile yet. Filename: src/lib.rs @@ -124,8 +124,8 @@ want to return the parts of that text that match, we know `contents` is the argument that should be connected to the return value using the lifetime syntax. Other programming languages don’t require you to connect arguments to return -values in the signature. So although this might seem strange, it will get -easier over time. You might want to compare this example with the “Validating +values in the signature. Although this might seem strange, it will get easier +over time. You might want to compare this example with the “Validating References with Lifetimes” section in Chapter 10. Now let’s run the test: @@ -177,7 +177,7 @@ Let’s work through each step, starting with iterating through lines. Rust has a helpful method to handle line-by-line iteration of strings, conveniently named `lines`, that works as shown in Listing 12-17. Note this -won’t compile yet: +won’t compile yet. Filename: src/lib.rs @@ -202,7 +202,7 @@ in a collection. Next, we’ll check whether the current line contains our query string. Fortunately, strings have a helpful method named `contains` that does this for us! Add a call to the `contains` method in the `search` function, as shown in -Listing 12-18. Note this still won’t compile yet: +Listing 12-18. Note this still won’t compile yet. Filename: src/lib.rs @@ -224,7 +224,7 @@ line contains the string in `query` We also need a way to store the lines that contain our query string. For that, we can make a mutable vector before the `for` loop and call the `push` method to store a `line` in the vector. After the `for` loop, we return the vector, as -shown in Listing 12-19: +shown in Listing 12-19. Filename: src/lib.rs diff --git a/src/doc/book/second-edition/src/ch12-05-working-with-environment-variables.md b/src/doc/book/second-edition/src/ch12-05-working-with-environment-variables.md index 78a4713279..1c7c2960aa 100644 --- a/src/doc/book/second-edition/src/ch12-05-working-with-environment-variables.md +++ b/src/doc/book/second-edition/src/ch12-05-working-with-environment-variables.md @@ -14,7 +14,7 @@ the environment variable is on. We’ll continue to follow the TDD process, so the first step is again to write a failing test. We’ll add a new test for the new `search_case_insensitive` function and rename our old test from `one_result` to `case_sensitive` to clarify the differences between the two -tests, as shown in Listing 12-20: +tests, as shown in Listing 12-20. Filename: src/lib.rs @@ -60,7 +60,7 @@ case-insensitive function we’re about to add Note that we’ve edited the old test’s `contents` too. We’ve added a new line with the text `"Duct tape."` using a capital D that shouldn’t match the query -“duct” when we’re searching in a case-sensitive manner. Changing the old test +`"duct"` when we’re searching in a case-sensitive manner. Changing the old test in this way helps ensure that we don’t accidentally break the case-sensitive search functionality that we’ve already implemented. This test should pass now and should continue to pass as we work on the case-insensitive search. @@ -84,7 +84,7 @@ they’ll be the same case when we check whether the line contains the query. Filename: src/lib.rs ```rust -fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let query = query.to_lowercase(); let mut results = Vec::new(); @@ -132,8 +132,8 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Great! They passed. Now, let’s call the new `search_case_insensitive` function from the `run` function. First, we’ll add a configuration option to the `Config` struct to switch between case-sensitive and case-insensitive search. -Adding this field will cause compiler errors since we aren’t initializing this -field anywhere yet: +Adding this field will cause compiler errors because we aren’t initializing +this field anywhere yet: Filename: src/lib.rs @@ -149,7 +149,7 @@ Note that we added the `case_sensitive` field that holds a Boolean. Next, we need the `run` function to check the `case_sensitive` field’s value and use that to decide whether to call the `search` function or the `search_case_insensitive` function, as shown in Listing 12-22. Note this still -won’t compile yet: +won’t compile yet. Filename: src/lib.rs @@ -162,7 +162,7 @@ won’t compile yet: # vec![] # } # -# fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +# pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { # vec![] # } # @@ -198,9 +198,9 @@ pub fn run(config: Config) -> Result<(), Box> { Finally, we need to check for the environment variable. The functions for working with environment variables are in the `env` module in the standard library, so we want to bring that module into scope with a `use std::env;` line -at the top of *src/lib.rs*. Then we’ll use the `var` method from the `env` +at the top of *src/lib.rs*. Then we’ll use the `var` function from the `env` module to check for an environment variable named `CASE_INSENSITIVE`, as shown -in Listing 12-23: +in Listing 12-23. Filename: src/lib.rs @@ -235,7 +235,7 @@ impl Config { Here, we create a new variable `case_sensitive`. To set its value, we call the `env::var` function and pass it the name of the `CASE_INSENSITIVE` environment -variable. The `env::var` method returns a `Result` that will be the successful +variable. The `env::var` function returns a `Result` that will be the successful `Ok` variant that contains the value of the environment variable if the environment variable is set. It will return the `Err` variant if the environment variable is not set. diff --git a/src/doc/book/second-edition/src/ch13-01-closures.md b/src/doc/book/second-edition/src/ch13-01-closures.md index f13a60b2cf..7c7747e9bf 100644 --- a/src/doc/book/second-edition/src/ch13-01-closures.md +++ b/src/doc/book/second-edition/src/ch13-01-closures.md @@ -25,7 +25,7 @@ it once so we don’t make the user wait more than necessary. We’ll simulate calling this hypothetical algorithm with the function `simulated_expensive_calculation` shown in Listing 13-1, which will print `calculating slowly...`, wait for two seconds, and then return whatever number -we passed in: +we passed in. Filename: src/main.rs @@ -57,7 +57,7 @@ The required inputs are these: * A random number that will generate some variety in the workout plans The output will be the recommended workout plan. Listing 13-2 shows the `main` -function we’ll use: +function we’ll use. Filename: src/main.rs @@ -160,7 +160,7 @@ to call it if the result isn’t needed, and we still want to call it only once. We could restructure the workout program in many ways. First, we’ll try extracting the duplicated call to the `simulated_expensive_calculation` -function into a variable, as shown in Listing 13-4: +function into a variable, as shown in Listing 13-4. Filename: src/main.rs @@ -219,7 +219,7 @@ Instead of always calling the `simulated_expensive_calculation` function before the `if` blocks, we can define a closure and store the *closure* in a variable rather than storing the result of the function call, as shown in Listing 13-5. We can actually move the whole body of `simulated_expensive_calculation` within -the closure we’re introducing here: +the closure we’re introducing here. Filename: src/main.rs @@ -250,7 +250,7 @@ closure—these are optional if the closure body is a single expression. The end of the closure, after the curly brackets, needs a semicolon to complete the `let` statement. The value returned from the last line in the closure body (`num`) will be the value returned from the closure when it’s called, because -that line doesn’t end in a semicolon; just like in function bodies. +that line doesn’t end in a semicolon; just as in function bodies. Note that this `let` statement means `expensive_closure` contains the *definition* of an anonymous function, not the *resulting value* of calling the @@ -262,7 +262,7 @@ With the closure defined, we can change the code in the `if` blocks to call the closure to execute the code and get the resulting value. We call a closure like we do a function: we specify the variable name that holds the closure definition and follow it with parentheses containing the argument values we -want to use, as shown in Listing 13-6: +want to use, as shown in Listing 13-6. Filename: src/main.rs @@ -336,7 +336,7 @@ available. As with variables, we can add type annotations if we want to increase explicitness and clarity at the cost of being more verbose than is strictly necessary. Annotating the types for the closure we defined in Listing 13-5 -would look like the definition shown in Listing 13-7: +would look like the definition shown in Listing 13-7. Filename: src/main.rs @@ -447,7 +447,7 @@ case, our closure has a parameter of type `u32` and returns a `u32`, so the trait bound we specify is `Fn(u32) -> u32`. Listing 13-9 shows the definition of the `Cacher` struct that holds a closure -and an optional result value: +and an optional result value. Filename: src/main.rs @@ -482,7 +482,7 @@ the result of the closure again, instead of executing the closure again, the `Cacher` will return the result held in the `Some` variant. The logic around the `value` field we’ve just described is defined in Listing -13-10: +13-10. Filename: src/main.rs @@ -540,7 +540,7 @@ If `self.value` is `None`, the code calls the closure stored in returns the value as well. Listing 13-11 shows how we can use this `Cacher` struct in the function -`generate_workout` from Listing 13-6: +`generate_workout` from Listing 13-6. Filename: src/main.rs @@ -649,7 +649,7 @@ fn call_with_different_values() { This test creates a new `Cacher` instance with a closure that returns the value passed into it. We call the `value` method on this `Cacher` instance with an `arg` value of 1 and then an `arg` value of 2, and we expect the call to -`value` with the `arg` value of 2 should return 2. +`value` with the `arg` value of 2 to return 2. Run this test with the `Cacher` implementation in Listing 13-9 and Listing 13-10, and the test will fail on the `assert_eq!` with this message: @@ -686,7 +686,7 @@ have: they can capture their environment and access variables from the scope in which they’re defined. Listing 13-12 has an example of a closure stored in the `equal_to_x` variable -that uses the `x` variable from the closure’s surrounding environment: +that uses the `x` variable from the closure’s surrounding environment. Filename: src/main.rs diff --git a/src/doc/book/second-edition/src/ch13-02-iterators.md b/src/doc/book/second-edition/src/ch13-02-iterators.md index 671077c3e5..9853ff1747 100644 --- a/src/doc/book/second-edition/src/ch13-02-iterators.md +++ b/src/doc/book/second-edition/src/ch13-02-iterators.md @@ -8,7 +8,7 @@ have to reimplement that logic yourself. In Rust, iterators are *lazy*, meaning they have no effect until you call methods that consume the iterator to use it up. For example, the code in Listing 13-13 creates an iterator over the items in the vector `v1` by calling -the `iter` method defined on `Vec`. This code by itself doesn’t do anything +the `iter` method defined on `Vec`. This code by itself doesn’t do anything useful. ```rust @@ -58,7 +58,7 @@ All iterators implement a trait named `Iterator` that is defined in the standard library. The definition of the trait looks like this: ```rust -trait Iterator { +pub trait Iterator { type Item; fn next(&mut self) -> Option; @@ -81,7 +81,7 @@ The `Iterator` trait only requires implementors to define one method: the We can call the `next` method on iterators directly; Listing 13-15 demonstrates what values are returned from repeated calls to `next` on the iterator created -from the vector: +from the vector. Filename: src/lib.rs diff --git a/src/doc/book/second-edition/src/ch14-01-release-profiles.md b/src/doc/book/second-edition/src/ch14-01-release-profiles.md index cc3f3f9aca..c150f6a073 100644 --- a/src/doc/book/second-edition/src/ch14-01-release-profiles.md +++ b/src/doc/book/second-edition/src/ch14-01-release-profiles.md @@ -41,10 +41,10 @@ opt-level = 3 The `opt-level` setting controls the number of optimizations Rust will apply to your code, with a range of 0 to 3. Applying more optimizations extends compiling time, so if you’re in development and compiling your code often, -you'll want faster compiling even if the resulting code runs slower. That is +you’ll want faster compiling even if the resulting code runs slower. That is the reason the default `opt-level` for `dev` is `0`. When you’re ready to release your code, it’s best to spend more time compiling. You’ll only compile -in release mode once, but you'll run the compiled program many times, so +in release mode once, but you’ll run the compiled program many times, so release mode trades longer compile time for code that runs faster. That is why the default `opt-level` for the `release` profile is `3`. diff --git a/src/doc/book/second-edition/src/ch14-02-publishing-to-crates-io.md b/src/doc/book/second-edition/src/ch14-02-publishing-to-crates-io.md index 28e423a979..d894b8c1dd 100644 --- a/src/doc/book/second-edition/src/ch14-02-publishing-to-crates-io.md +++ b/src/doc/book/second-edition/src/ch14-02-publishing-to-crates-io.md @@ -153,7 +153,7 @@ including the comment describing the crate as a whole Documentation comments within items are useful for describing crates and modules especially. Use them to explain the overall purpose of the container to -help your users understand the crate's organization. +help your users understand the crate’s organization. ### Exporting a Convenient Public API with `pub use` diff --git a/src/doc/book/second-edition/src/ch14-04-installing-binaries.md b/src/doc/book/second-edition/src/ch14-04-installing-binaries.md index 826b970dd1..2faf6edd35 100644 --- a/src/doc/book/second-edition/src/ch14-04-installing-binaries.md +++ b/src/doc/book/second-edition/src/ch14-04-installing-binaries.md @@ -12,7 +12,7 @@ information in the *README* file about whether a crate is a library, has a binary target, or both. All binaries installed with `cargo install` are stored in the installation -root’s *bin* folder. If you installed Rust using *rustup.rs* and don’t have any +root’s *bin* folder. If you installed Rust using `rustup` and don’t have any custom configurations, this directory will be *$HOME/.cargo/bin*. Ensure that directory is in your `$PATH` to be able to run programs you’ve installed with `cargo install`. diff --git a/src/doc/book/second-edition/src/ch16-01-threads.md b/src/doc/book/second-edition/src/ch16-01-threads.md index b705c41a51..ba46b73b11 100644 --- a/src/doc/book/second-edition/src/ch16-01-threads.md +++ b/src/doc/book/second-edition/src/ch16-01-threads.md @@ -124,7 +124,7 @@ for the operating system to switch between the threads. ### Waiting for All Threads to Finish Using `join` Handles The code in Listing 16-1 not only stops the spawned thread prematurely most of -the time due to the main thread ending, but also can't guarantee that the +the time due to the main thread ending, but also can’t guarantee that the spawned thread will get to run at all. The reason is that there is no guarantee on the order in which threads run! diff --git a/src/doc/book/second-edition/src/ch16-02-message-passing.md b/src/doc/book/second-edition/src/ch16-02-message-passing.md index cdd490177a..6b3226615e 100644 --- a/src/doc/book/second-edition/src/ch16-02-message-passing.md +++ b/src/doc/book/second-edition/src/ch16-02-message-passing.md @@ -3,8 +3,8 @@ One increasingly popular approach to ensuring safe concurrency is *message passing*, where threads or actors communicate by sending each other messages containing data. Here’s the idea in a slogan from [the Go language -documentation](http://golang.org/doc/effective_go.html): "Do not communicate by -sharing memory; instead, share memory by communicating." +documentation](http://golang.org/doc/effective_go.html): “Do not communicate by +sharing memory; instead, share memory by communicating.” One major tool Rust has for accomplishing message-sending concurrency is the *channel*, a programming concept that Rust’s standard library provides an @@ -165,7 +165,7 @@ advantage of thinking about ownership throughout your Rust programs. Let’s do an experiment to show how channels and ownership work together to prevent problems: we’ll try to use a `val` value in the spawned thread *after* we’ve sent it down the channel. Try compiling the code in Listing 16-9 to see why -this code isn't allowed: +this code isn’t allowed: Filename: src/main.rs diff --git a/src/doc/book/second-edition/src/ch17-01-what-is-oo.md b/src/doc/book/second-edition/src/ch17-01-what-is-oo.md index 3ce206e21f..bf1b5cb9e4 100644 --- a/src/doc/book/second-edition/src/ch17-01-what-is-oo.md +++ b/src/doc/book/second-edition/src/ch17-01-what-is-oo.md @@ -115,13 +115,13 @@ code to read the `average` but not modify it. Because we’ve encapsulated the implementation details of the struct `AveragedCollection`, we can easily change aspects, such as the data structure, -in the future. For instance, we could use a `HashSet` instead of a `Vec` for -the `list` field. As long as the signatures of the `add`, `remove`, and -`average` public methods stay the same, code using `AveragedCollection` -wouldn’t need to change. If we made `list` public instead, this wouldn’t -necessarily be the case: `HashSet` and `Vec` have different methods for adding -and removing items, so the external code would likely have to change if it were -modifying `list` directly. +in the future. For instance, we could use a `HashSet` instead of a +`Vec` for the `list` field. As long as the signatures of the `add`, +`remove`, and `average` public methods stay the same, code using +`AveragedCollection` wouldn’t need to change. If we made `list` public instead, +this wouldn’t necessarily be the case: `HashSet` and `Vec` have +different methods for adding and removing items, so the external code would +likely have to change if it were modifying `list` directly. If encapsulation is a required aspect for a language to be considered object oriented, then Rust meets that requirement. The option to use `pub` or not for diff --git a/src/doc/book/second-edition/src/ch17-02-trait-objects.md b/src/doc/book/second-edition/src/ch17-02-trait-objects.md index fcccc11825..d90a11dfb5 100644 --- a/src/doc/book/second-edition/src/ch17-02-trait-objects.md +++ b/src/doc/book/second-edition/src/ch17-02-trait-objects.md @@ -159,9 +159,9 @@ collections, using generics and trait bounds is preferable because the definitions will be monomorphized at compile time to use the concrete types. On the other hand, with the method using trait objects, one `Screen` instance -can hold a `Vec` that contains a `Box