diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54c507304f..70376c120f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -301,12 +301,12 @@ It's absolutely fine to have multiple build directories with different [pull-requests]: #pull-requests Pull requests are the primary mechanism we use to change Rust. GitHub itself -has some [great documentation][pull-requests] on using the Pull Request feature. +has some [great documentation][about-pull-requests] on using the Pull Request feature. We use the "fork and pull" model [described here][development-models], where contributors push changes to their personal fork and create pull requests to bring those changes into the source repository. -[pull-requests]: https://help.github.com/articles/about-pull-requests/ +[about-pull-requests]: https://help.github.com/articles/about-pull-requests/ [development-models]: https://help.github.com/articles/about-collaborative-development-models/ Please make pull requests against the `master` branch. diff --git a/RELEASES.md b/RELEASES.md index e1f4a56646..d6f95f5207 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,16 +1,3 @@ -Version 1.24.1 (2018-03-01) -========================== - - - [Do not abort when unwinding through FFI][48251] - - [Emit UTF-16 files for linker arguments on Windows][48318] - - [Make the error index generator work again][48308] - - [Cargo will warn on Windows 7 if an update is needed][cargo/5069]. - -[48251]: https://github.com/rust-lang/rust/issues/48251 -[48308]: https://github.com/rust-lang/rust/issues/48308 -[48318]: https://github.com/rust-lang/rust/issues/48318 -[cargo/5069]: https://github.com/rust-lang/cargo/pull/5069 - Version 1.24.0 (2018-02-15) ========================== @@ -165,7 +152,6 @@ Stabilized APIs Cargo ----- -- [Cargo now supports alternative registries][cargo/4506] - [Cargo now supports uninstallation of multiple packages][cargo/4561] eg. `cargo uninstall foo bar` uninstalls `foo` and `bar`. - [Added unit test checking to `cargo check`][cargo/4592] @@ -176,7 +162,6 @@ Misc ---- - [Releases now ship with the Cargo book documentation.][45692] - [rustdoc now prints rendering warnings on every run.][45324] -- [Release tarballs now come with rustfmt][45903] Compatibility Notes ------------------- @@ -210,9 +195,7 @@ Compatibility Notes [45852]: https://github.com/rust-lang/rust/issues/45852 [45853]: https://github.com/rust-lang/rust/pull/45853 [45887]: https://github.com/rust-lang/rust/pull/45887 -[45903]: https://github.com/rust-lang/rust/pull/45903 [45920]: https://github.com/rust-lang/rust/pull/45920 -[cargo/4506]: https://github.com/rust-lang/cargo/pull/4506 [cargo/4561]: https://github.com/rust-lang/cargo/pull/4561 [cargo/4592]: https://github.com/rust-lang/cargo/pull/4592 [cargo/4637]: https://github.com/rust-lang/cargo/pull/4637 @@ -708,7 +691,7 @@ Compatibility Notes a warning. - [From the pound escape, lines consisting of multiple `#`s are now visible][41785] -- [It is an error to reexport private enum variants][42460]. This is +- [It is an error to re-export private enum variants][42460]. This is known to break a number of crates that depend on an older version of mustache. - [On Windows, if `VCINSTALLDIR` is set incorrectly, `rustc` will try @@ -2382,10 +2365,10 @@ Rustdoc ------- * [Fix empty implementation section on some module pages](https://github.com/rust-lang/rust/pull/34536) -* [Fix inlined renamed reexports in import lists](https://github.com/rust-lang/rust/pull/34479) +* [Fix inlined renamed re-exports in import lists](https://github.com/rust-lang/rust/pull/34479) * [Fix search result layout for enum variants and struct fields](https://github.com/rust-lang/rust/pull/34477) * [Fix issues with source links to external crates](https://github.com/rust-lang/rust/pull/34387) -* [Fix redirect pages for renamed reexports](https://github.com/rust-lang/rust/pull/34245) +* [Fix redirect pages for renamed re-exports](https://github.com/rust-lang/rust/pull/34245) Tooling ------- @@ -5119,7 +5102,7 @@ Version 0.10 (2014-04-03) * std: The `vec` module has been renamed to `slice`. * std: A new vector type, `Vec`, has been added in preparation for DST. This will become the only growable vector in the future. - * std: `std::io` now has more public-reexports. Types such as `BufferedReader` + * std: `std::io` now has more public re-exports. Types such as `BufferedReader` are now found at `std::io::BufferedReader` instead of `std::io::buffered::BufferedReader`. * std: `print` and `println` are no longer in the prelude, the `print!` and @@ -5210,8 +5193,8 @@ Version 0.10 (2014-04-03) * render standalone markdown files. * the --test flag tests all code blocks by default. * exported macros are displayed. - * reexported types have their documentation inlined at the location of the - first reexport. + * re-exported types have their documentation inlined at the location of the + first re-export. * search works across crates that have been rendered to the same output directory. @@ -5598,7 +5581,7 @@ Version 0.7 (2013-07-03) incl. `any`, `all`. removed. * std: The `finalize` method of `Drop` renamed to `drop`. * std: The `drop` method now takes `&mut self` instead of `&self`. - * std: The prelude no longer reexports any modules, only types and traits. + * std: The prelude no longer re-exports any modules, only types and traits. * std: Prelude additions: `print`, `println`, `FromStr`, `ApproxEq`, `Equiv`, `Iterator`, `IteratorUtil`, many numeric traits, many tuple traits. * std: New numeric traits: `Fractional`, `Real`, `RealExt`, `Integer`, `Ratio`, diff --git a/config.toml.example b/config.toml.example index 18c1f160c0..f153562a53 100644 --- a/config.toml.example +++ b/config.toml.example @@ -151,6 +151,10 @@ # default. #extended = false +# Installs choosen set of extended tools if enables. By default builds all. +# If choosen tool failed to build the installation fails. +#tools = ["cargo", "rls", "rustfmt", "analysis", "src"] + # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose #verbose = 0 @@ -235,6 +239,11 @@ # compiler. #codegen-units = 1 +# Whether to enable ThinLTO (and increase the codegen units to either a default +# or the configured value). On by default. If we want the fastest possible +# compiler, we should disable this. +#thinlto = true + # Whether or not debug assertions are enabled for the compiler and standard # library. Also enables compilation of debug! and trace! logging macros. #debug-assertions = false @@ -290,7 +299,7 @@ # Flag indicating whether git info will be retrieved from .git automatically. # Having the git information can cause a lot of rebuilds during development. -# Note: If this attribute is not explicity set (e.g. if left commented out) it +# Note: If this attribute is not explicitly set (e.g. if left commented out) it # will default to true if channel = "dev", but will default to false otherwise. #ignore-git = true @@ -305,6 +314,18 @@ # result (broken, compiling, testing) into this JSON file. #save-toolstates = "/path/to/toolstates.json" +# This is an array of the codegen backends that will be compiled for the rustc +# that's being compiled. The default is to only build the LLVM codegen backend, +# but you can also optionally enable the "emscripten" backend for asm.js or +# make this an empty array (but that probably won't get too far in the +# bootstrap) +#codegen-backends = ["llvm"] + +# Flag indicating whether `libstd` calls an imported function to handle basic IO +# when targeting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown` +# target, as without this option the test output will not be captured. +#wasm-syscall = false + # ============================================================================= # Options for specific targets # @@ -332,7 +353,7 @@ #linker = "cc" # Path to the `llvm-config` binary of the installation of a custom LLVM to link -# against. Note that if this is specifed we don't compile LLVM at all for this +# against. Note that if this is specified we don't compile LLVM at all for this # target. #llvm-config = "../path/to/llvm/root/bin/llvm-config" diff --git a/git-commit-hash b/git-commit-hash index 52f9237c53..de46bbefc9 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -d3ae9a9e08edf12de0ed82af57ba2a56c26496ea \ No newline at end of file +84203cac67e65ca8640b8392348411098c856985 \ No newline at end of file diff --git a/src/Cargo.lock b/src/Cargo.lock index 56db3ad74a..8a4254197c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -28,7 +28,7 @@ name = "alloc" version = "0.0.0" dependencies = [ "core 0.0.0", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "std_unicode 0.0.0", ] @@ -39,7 +39,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.0.0", ] @@ -69,28 +69,33 @@ name = "arena" version = "0.0.0" [[package]] -name = "atty" -version = "0.2.3" +name = "arrayvec" +version = "0.4.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)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace" -version = "0.3.4" +version = "0.3.5" 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)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dbghelp-sys 0.2.0 (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.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -98,8 +103,8 @@ name = "backtrace-sys" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -126,16 +131,16 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.14 (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.15 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -153,8 +158,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -162,7 +167,7 @@ dependencies = [ name = "build_helper" version = "0.1.0" dependencies = [ - "filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -172,51 +177,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.25.0" +version = "0.26.0" dependencies = [ - "atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cargotest 0.1.0", - "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.14.0", - "crossbeam 0.3.0 (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.15.0", + "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.8 (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.34 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "psapi-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (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]] @@ -224,9 +228,9 @@ name = "cargo_metadata" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -236,25 +240,37 @@ 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.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cargo_metadata" +version = "0.5.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.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cargotest" version = "0.1.0" dependencies = [ - "cargo 0.25.0", - "filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.26.0", + "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -263,7 +279,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -271,13 +287,22 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clap" version = "2.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -288,40 +313,60 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.174" +version = "0.0.186" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy-mini-macro-test 0.1.0", - "clippy_lints 0.0.174", - "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy-mini-macro-test 0.2.0", + "clippy_lints 0.0.186", + "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy-mini-macro-test" -version = "0.1.0" +version = "0.2.0" [[package]] name = "clippy_lints" -version = "0.0.174" +version = "0.0.186" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (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.0.15 (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.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clippy_lints" +version = "0.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.6 (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.0 (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.3 (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.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -329,16 +374,7 @@ name = "cmake" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "coco" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -354,14 +390,14 @@ name = "commoncrypto-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -371,25 +407,25 @@ version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.14 (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.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest_rs" -version = "0.3.3" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.14 (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.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -407,42 +443,68 @@ version = "0.0.0" [[package]] name = "core-foundation" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crates-io" -version = "0.14.0" +version = "0.15.0" dependencies = [ - "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam" -version = "0.2.10" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "crossbeam" +name = "crossbeam-deque" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.2.2" +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)", +] [[package]] name = "crypto-hash" @@ -482,38 +544,31 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.1 (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.39 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curl-sys" -version = "0.3.15" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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.23 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.24 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dbghelp-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -552,13 +607,13 @@ dependencies = [ [[package]] name = "docopt" -version = "0.8.1" +version = "0.8.3" 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)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -611,7 +666,19 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.0 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -619,7 +686,7 @@ name = "error-chain" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -627,7 +694,7 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -642,7 +709,7 @@ name = "failure" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -662,12 +729,12 @@ version = "0.1.0" [[package]] name = "filetime" -version = "0.1.14" +version = "0.1.15" 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)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -683,7 +750,7 @@ name = "flate2" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -711,26 +778,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fs2" -version = "0.4.2" +version = "0.4.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)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -754,15 +820,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "git2" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -770,10 +836,10 @@ name = "git2-curl" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -783,14 +849,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.2.1" +version = "0.3.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)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -815,9 +881,9 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -825,6 +891,11 @@ name = "hex" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "home" version = "0.3.0" @@ -839,7 +910,7 @@ dependencies = [ [[package]] name = "html-diff" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kuchiki 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -874,17 +945,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ignore" -version = "0.2.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.3.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)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -908,12 +981,18 @@ dependencies = [ "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "is-match" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "itertools" version = "0.6.5" @@ -922,6 +1001,14 @@ dependencies = [ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.3.4" @@ -929,11 +1016,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jobserver" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -948,9 +1035,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -975,14 +1062,14 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.16.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1001,6 +1088,11 @@ name = "lazycell" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazycell" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.0.0" @@ -1010,21 +1102,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.34" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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)", - "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1034,9 +1126,9 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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.23 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1045,8 +1137,8 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1084,9 +1176,9 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (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.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1115,23 +1207,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.26" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.6 (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)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1139,15 +1236,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1155,16 +1244,21 @@ name = "memchr" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memoffset" +version = "0.2.1" +source = "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.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1178,15 +1272,24 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "miow" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "socket2 0.3.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 = "miri" version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.6 (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.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1200,7 +1303,7 @@ 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)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1217,10 +1320,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (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.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "num" version = "0.1.41" @@ -1241,7 +1349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1289,10 +1397,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1308,8 +1416,8 @@ dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (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.34 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1319,11 +1427,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.23" +version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1379,8 +1487,8 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1418,7 +1526,7 @@ version = "0.7.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1457,19 +1565,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] -[[package]] -name = "psapi-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pulldown-cmark" version = "0.0.15" @@ -1528,37 +1627,37 @@ dependencies = [ [[package]] name = "rand" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "0.9.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "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.39 (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.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.32" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1566,7 +1665,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1591,12 +1690,12 @@ dependencies = [ [[package]] name = "regex" -version = "0.2.3" +version = "0.2.5" 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.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (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)", ] @@ -1608,9 +1707,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex-syntax" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex-syntax" +version = "0.5.3" +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" @@ -1621,57 +1728,66 @@ version = "0.1.0" [[package]] name = "rls" -version = "0.124.0" +version = "0.125.1" dependencies = [ - "cargo 0.25.0", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.26.0", + "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.188 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (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.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.31.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.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-blacklist 0.1.0 (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.1 (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.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.3.4", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-analysis" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.15.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)", ] +[[package]] +name = "rls-blacklist" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rls-data" -version = "0.14.0" +version = "0.15.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)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-rustc" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1680,13 +1796,13 @@ version = "0.4.0" 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)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-vfs" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1698,7 +1814,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1706,13 +1822,13 @@ name = "rustc" version = "0.0.0" dependencies = [ "arena 0.0.0", - "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.5 (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.1 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_apfloat 0.0.0", "rustc_back 0.0.0", @@ -1724,6 +1840,72 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc-ap-rustc_cratesio_shim" +version = "29.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)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-ap-rustc_data_structures" +version = "29.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)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (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 = "29.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 29.0.0 (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)", +] + +[[package]] +name = "rustc-ap-serialize" +version = "29.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-ap-syntax" +version = "29.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 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 29.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-syntax_pos" +version = "29.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (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)", +] + [[package]] name = "rustc-demangle" version = "0.1.5" @@ -1776,7 +1958,7 @@ name = "rustc_back" version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -1785,9 +1967,9 @@ dependencies = [ name = "rustc_binaryen" version = "0.0.0" dependencies = [ - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1870,7 +2052,6 @@ dependencies = [ "rustc_privacy 0.0.0", "rustc_resolve 0.0.0", "rustc_save_analysis 0.0.0", - "rustc_trans 0.0.0", "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", "serialize 0.0.0", @@ -1895,7 +2076,7 @@ version = "0.0.0" dependencies = [ "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -1920,7 +2101,8 @@ 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.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -1968,7 +2150,6 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", - "rustc_trans_utils 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -2041,7 +2222,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.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.15.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)", @@ -2056,11 +2237,12 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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.7.0 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", @@ -2091,6 +2273,8 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_data_structures 0.0.0", + "rustc_incremental 0.0.0", + "rustc_mir 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2127,12 +2311,16 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "html-diff 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "html-diff 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustdoc-themes" +version = "0.1.0" + [[package]] name = "rustdoc-tool" version = "0.0.0" @@ -2142,7 +2330,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "0.3.4" +version = "0.3.8" dependencies = [ "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2150,12 +2338,40 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (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.34 (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.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (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.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustfmt-nightly" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.0 (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.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.15 (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.39 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2171,6 +2387,23 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "same-file" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "schannel" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.0.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 = "scoped-tls" version = "0.1.0" @@ -2215,7 +2448,16 @@ 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.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.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.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2225,22 +2467,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.18.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2252,18 +2494,18 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2276,7 +2518,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2285,6 +2527,11 @@ name = "shell-escape" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "siphasher" version = "0.2.2" @@ -2302,14 +2549,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" -version = "0.2.4" +version = "0.3.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)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2331,7 +2576,7 @@ dependencies = [ "panic_abort 0.0.0", "panic_unwind 0.0.0", "profiler_builtins 0.0.0", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -2356,7 +2601,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2447,7 +2692,7 @@ name = "syntex_errors" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2469,7 +2714,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2483,9 +2728,9 @@ name = "tar" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.32 (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.39 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2494,7 +2739,7 @@ name = "tempdir" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2533,8 +2778,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2560,7 +2805,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2589,8 +2834,8 @@ name = "time" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (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)", ] @@ -2607,9 +2852,26 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml-query" +version = "0.6.0" +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)", + "is-match 0.1.0 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -2676,7 +2938,7 @@ dependencies = [ [[package]] name = "url" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2689,8 +2951,8 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2745,6 +3007,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "walkdir" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -2801,12 +3071,12 @@ name = "xattr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "xz2" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lzma-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2823,8 +3093,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31" -"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" -"checksum backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8709cc7ec06f6f0ae6c2c7e12f6ed41540781f72b488d83734978295ceae182e" +"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859" +"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "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" @@ -2833,28 +3104,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" "checksum cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6fb2b5574726329c85cdba0df0347fddfec3cf9c8b588f9931708280f5643" -"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" +"checksum cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5caae26de3704081ef638f87f05a6891b04f2b7d5ce9429a3de21095528ae22" +"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" +"checksum clippy_lints 0.0.188 (registry+https://github.com/rust-lang/crates.io-index)" = "72f716a434a6c46467d1eebf4c7838aca9fa1a573da30099adc4310a2201e8f0" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" -"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "562bafeec9aef1e3e08f1c5b0c542220bb80ff2894e5373a1f9d17c346412c66" -"checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e" -"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5" -"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum crossbeam 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8837ab96533202c5b610ed44bc7f4183e7957c1c8f56e8cc78bb098593c8ba0a" +"checksum compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6c5aafb5d4a77c6b5fa384fe93c7a9a3561bd88c4b8b8e45187cf5e779b1badc" +"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 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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59796cc6cbbdc6bb319161349db0c3250ec73ec7fcb763a51065ec4e2e158552" +"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34903878eec1694faf53cae8473a088df333181de421d4d3d48061d6559fe602" "checksum cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef6124306e5ebc5ab11891d063aeafdd0cdc308079b708c8b566125f3680292b" "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df" -"checksum curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7034c534a1d7d22f7971d6088aa9d281d219ef724026c3428092500f41ae9c2c" -"checksum curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4bee31aa3a079d5f3ff9579ea4dcfb1b1a17a40886f5f467436d383e78134b55" -"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e" +"checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" "checksum derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "415f627ab054041c3eb748c2e1da0ef751989f5f0c386b63a098e545854a98ba" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" -"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" +"checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" @@ -2862,47 +3136,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" +"checksum env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f15f0b172cb4f52ed5dbf47f774a387cd2315d1bf7894ab5af9b083ae27efa5a" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" -"checksum filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "aa75ec8f7927063335a9583e7fa87b0110bb888cf766dc01b54c0ff70d760c8e" +"checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866" -"checksum fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd510087c325af53ba24f3be8f1c081b0982319adcb8b03cad764512923ccc19" -"checksum fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "08b3a6f13ad6b96572b53ce7af74543132f1a7055ccceb6d073dd36c54481859" +"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3" "checksum futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "118b49cac82e04121117cbd3121ede3147e885627d82c4546b87c702debb90c1" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum git2 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "40a111aecd59985496012976beca164b4f6c930d507a099831e06b07f19d54f1" +"checksum git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5b4bb7cd2a44e6e5ee3a26ba6a9ca10d4ce2771cdc3839bbc54b47b7d1be84" "checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "464627f948c3190ae3d04b1bc6d7dca2f785bda0ac01278e6db129ad383dbeb6" +"checksum globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96ab92362c06811385ae9a34d2698e8a1160745e0c78fbb434a44c8de3fabc" "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" +"checksum hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "459d3cf58137bb02ad4adeef5036377ff59f066dbb82517b7192e3a5462a2abc" "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db" -"checksum html-diff 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9778743e3b3c3679f471f0ed1833c690f19f4a0919e33b281f12ef5f77ad64c6" +"checksum html-diff 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4cfdf62a484a3ac0d9b80f562d37f99366db08a63621b917ea3056565345f7" "checksum html5ever 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb46978eb757a603b7dfe2dafb1c62cb4dee3428d8ac1de734d83d6b022d06" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" -"checksum ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fcaf2365eb14b28ec7603c98c06cc531f19de9eb283d89a3dff8417c8c99f5" +"checksum ignore 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f3a099daf09006b27e37fa8b9bbb49ddc5867ffe2d663bb56b1b8d672774aa6" +"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" "checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21" +"checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" -"checksum jobserver 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "931b04e5e57d88cc909528f0d701db36a870b72a052648ded8baf80f9f445e0f" +"checksum jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "565f6106bd87b394398f813bea4e5ecad6d6b0f6aa077592d088f882a506481d" "checksum json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)" = "39ebf0fac977ee3a4a3242b6446004ff64514889e3e2730bbd4f764a67a2e483" "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 kuchiki 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e03098e8e719c92b7794515dfd5c1724e2b12f5ce1788e61cfa4663f82eba8d8" -"checksum languageserver-types 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "773e175c945800aeea4c21c04090bcb9db987b1a566ad9c6f569972299950e3e" +"checksum languageserver-types 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d25086d59f44b80253d5ff96c66a692fb69de8485cf7a25b28677e89126de0d" "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.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" -"checksum libgit2-sys 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "82fc20bd8beefe7c9f98aae2d3cff78e57f544cdd83d58fe181ec37a5fbe0c77" +"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" +"checksum libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6eeae66e7b1c995de45cb4e65c5ab438a96a7b4077e448645d4048dc753ad357" "checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -2912,15 +3191,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum markup5ever 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "047150a0e03b57e638fc45af33a0b63a0362305d5b9f92ecef81df472a4cceb0" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum mdbook 0.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "8a1ac668292d1e5c7b1c6fd64f70d3a85105b8069a89558a0d67bdb2ff298ca1" +"checksum mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fef236caad7ba3b5b3944df946f19ab3e190bca53c111dd00fe05fa8d879f2fd" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "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 miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" "checksum nibble_vec 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "62e678237a4c70c5f2b917cefd7d080dfbf800421f06e8a59d4e28ef5130fd9e" "checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487" +"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" "checksum num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "bdc1494b5912f088f260b775799468d9b9209ac60885d8186a547a0476289e23" "checksum num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "58de7b4bf7cf5dbecb635a5797d489864eadd03b107930cbccf9e0fd7428b47c" @@ -2928,11 +3209,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "0c7cb72a95250d8a370105c828f388932373e0e94414919891a0f945222310fe" "checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" "checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "2200ffec628e3f14c39fc0131a301db214f1a7d584e36507ee8700b0c7fb7a46" +"checksum openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "14ba54ac7d5a4eabd1d5f2c1fdeb7e7c14debfa669d94b983d01b465e767ba9e" "checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412" @@ -2946,7 +3227,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum procedural-masquerade 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1bcafee1590f81acb329ae45ec627b318123f085153913620316ae9a144b2a" -"checksum psapi-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f71c7e142c25f297077a8ebc21f10847096b5d21ad7619d7bf0c1fcecb40bb0" "checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b" "checksum pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a656fdb8b6848f896df5e478a0eb9083681663e37dcb77dd16981ff65329fe8b" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" @@ -2954,41 +3234,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "034f1c4528581c40a60e96875467c03315868084e08ff4ceb46a00f7be3b16b4" "checksum radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "211c49b6a9995cac0fd1dd9ca60b42cf3a51e151a12eb954b3a9e75513426ee8" -"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59" -"checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf" -"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" -"checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0" +"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" +"checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d" +"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" +"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.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" -"checksum regex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ac6ab4e9218ade5b423358bbd2567d1617418403c7a512603630181813316322" +"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rls-analysis 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "38841e3c5271715a574ac220d9b408b59ed9e2626909c3bc54b5853b4eaadb7b" -"checksum rls-data 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8024f1feaca72d0aa4ae1e2a8d454a31b9a33ed02f8d0e9c8559bf53c267ec3c" -"checksum rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b21ea952e9bf1569929abf1bb920262cde04b7b1b26d8e0260286302807299d2" +"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" +"checksum regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b2550876c31dc914696a6c2e01cbce8afba79a93c8ae979d2fe051c0230b3756" +"checksum rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4b9a3a3f2345854e39768e6425d1c893855da217183d1c0b3ff6f1664b6b6d" +"checksum rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56fb7b8e4850b988fbcf277fbdb1eff36879070d02fc1ca243b559273866973d" +"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" +"checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" -"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff" +"checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" +"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524" +"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad" +"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182" +"checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b" +"checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d" +"checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum rustfmt-nightly 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "554256054eae37ead2f799ffa9cf8be8249496c6c3cf005c28b7cfa55f4efaa5" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" +"checksum schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "acece75e0f987c48863a6c792ec8b7d6c4177d4a027f8ccc72f849794f437016" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum selectors 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c89b1c6a3c029c82263f7dd2d44d0005ee7374eb09e254ab59dede4353a8c0" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "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.25 (registry+https://github.com/rust-lang/crates.io-index)" = "386122ba68c214599c44587e0c0b411e8d90894503a95425b4f9508e4317901f" -"checksum serde_derive 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "ec0bfa6c5784e7d110514448da0e1dbad41ea5514c3e68be755b23858b83a399" -"checksum serde_derive_internals 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "730fe9f29fe8db69a601837f416e46cba07792031ed6b27557a43e49d62d89ae" +"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526" +"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0" +"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839" +"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" "checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc" "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" +"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 smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" -"checksum socket2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b4896961171cd3317c7e9603d88f379f8c6e45342212235d356496680c68fd" +"checksum socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf5d5aa364bf61a0d744a293da20381617b6445b89eb524800fab857c5aed2d8" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum string_cache 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "413fc7852aeeb5472f1986ef755f561ddf0c789d3d796e65f0b6fe293ecd4ef8" "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7" @@ -3013,6 +3306,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" +"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" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" @@ -3021,7 +3316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" +"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3" "checksum utf-8 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6f923c601c7ac48ef1d66f7d5b5b2d9a7ba9c51333ab75a3ddf8d0309185a56" @@ -3031,6 +3326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b6d201f4f8998a837196b6de9c73e35af14c992cbb92c4ab641d2c2dce52de" "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" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" @@ -3039,5 +3335,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a39ee4464208f6430992ff20154216ab2357772ac871d994c51628d60e58b8b0" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" -"checksum xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e9510bdf100731599107c61f77daf46713a69a568f75458999c1f9dbf6ba25b0" +"checksum xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df591c3504d014dd791d998123ed00a476c7e26dc6b2e873cb55c6ac9e59fa" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/src/Cargo.toml b/src/Cargo.toml index 15594a54ef..c03301852c 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -4,6 +4,7 @@ members = [ "rustc", "libstd", "libtest", + "librustc_trans", "tools/cargotest", "tools/clippy", "tools/compiletest", @@ -21,6 +22,7 @@ members = [ "tools/rls", "tools/rustfmt", "tools/miri", + "tools/rustdoc-themes", # FIXME(https://github.com/rust-lang/cargo/issues/4089): move these to exclude "tools/rls/test_data/bin_lib", "tools/rls/test_data/borrow_error", @@ -55,8 +57,18 @@ debug-assertions = false debug = false debug-assertions = false +# We want the RLS to use the version of Cargo that we've got vendored in this +# repository to ensure that the same exact version of Cargo is used by both the +# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository +# so we use a `[patch]` here to override the github repository with our local +# vendored copy. [patch."https://github.com/rust-lang/cargo"] cargo = { path = "tools/cargo" } [patch.crates-io] +# 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-nightly = { path = "tools/rustfmt" } diff --git a/src/binaryen/src/tools/asm2wasm.cpp b/src/binaryen/src/tools/asm2wasm.cpp index 3f70e0388e..cecae7a819 100644 --- a/src/binaryen/src/tools/asm2wasm.cpp +++ b/src/binaryen/src/tools/asm2wasm.cpp @@ -87,7 +87,7 @@ int main(int argc, const char *argv[]) { [&trapMode](Options *o, const std::string &argument) { try { trapMode = trapModeFromString(argument); - } catch (std::invalid_argument e) { + } catch (std::invalid_argument& e) { std::cerr << "Error: " << e.what() << "\n"; exit(EXIT_FAILURE); } diff --git a/src/binaryen/src/tools/s2wasm.cpp b/src/binaryen/src/tools/s2wasm.cpp index 6e7b2c05e2..3643993b7f 100644 --- a/src/binaryen/src/tools/s2wasm.cpp +++ b/src/binaryen/src/tools/s2wasm.cpp @@ -92,7 +92,7 @@ int main(int argc, const char *argv[]) { [&trapMode](Options *o, const std::string &argument) { try { trapMode = trapModeFromString(argument); - } catch (std::invalid_argument e) { + } catch (std::invalid_argument& e) { std::cerr << "Error: " << e.what() << "\n"; exit(EXIT_FAILURE); } diff --git a/src/binaryen/src/wasm/wasm-s-parser.cpp b/src/binaryen/src/wasm/wasm-s-parser.cpp index 0de3edf3f6..78a150f814 100644 --- a/src/binaryen/src/wasm/wasm-s-parser.cpp +++ b/src/binaryen/src/wasm/wasm-s-parser.cpp @@ -1408,9 +1408,9 @@ Name SExpressionWasmBuilder::getLabel(Element& s) { uint64_t offset; try { offset = std::stoll(s.c_str(), nullptr, 0); - } catch (std::invalid_argument) { + } catch (std::invalid_argument&) { throw ParseException("invalid break offset"); - } catch (std::out_of_range) { + } catch (std::out_of_range&) { throw ParseException("out of range break offset"); } if (offset > nameMapper.labelStack.size()) throw ParseException("invalid label", s.line, s.col); diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 37336a56d7..55d104b182 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -125,11 +125,6 @@ fn main() { cmd.arg(format!("-Clinker={}", target_linker)); } - // Pass down incremental directory, if any. - if let Ok(dir) = env::var("RUSTC_INCREMENTAL") { - cmd.arg(format!("-Zincremental={}", dir)); - } - let crate_name = args.windows(2) .find(|a| &*a[0] == "--crate-name") .unwrap(); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 6203759085..389b504c64 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -23,10 +23,17 @@ use std::path::PathBuf; fn main() { let args = env::args_os().skip(1).collect::>(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); - let libdir = env::var_os("RUSTC_LIBDIR").expect("RUSTC_LIBDIR was not set"); + let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); + use std::str::FromStr; + + let verbose = match env::var("RUSTC_VERBOSE") { + Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), + Err(_) => 0, + }; + let mut dylib_path = bootstrap::util::dylib_path(); dylib_path.insert(0, PathBuf::from(libdir)); @@ -63,6 +70,10 @@ fn main() { cmd.arg("--deny-render-differences"); } + if verbose > 1 { + eprintln!("rustdoc command: {:?}", cmd); + } + std::process::exit(match cmd.status() { Ok(s) => s.code().unwrap_or(1), Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 707aceebb1..603a97ddfd 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -351,11 +351,6 @@ class RustBuild(object): with open(self.rustc_stamp(), 'w') as rust_stamp: rust_stamp.write(self.date) - if "pc-windows-gnu" in self.build: - filename = "rust-mingw-{}-{}.tar.gz".format( - rustc_channel, self.build) - self._download_stage0_helper(filename, "rust-mingw") - if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.program_out_of_date(self.cargo_stamp())): @@ -607,6 +602,7 @@ 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["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): @@ -644,14 +640,23 @@ class RustBuild(object): os.path.join(self.rust_root, ".gitmodules"), "--get-regexp", "path"] ).decode(default_encoding).splitlines()] - submodules = [module for module in submodules - if not ((module.endswith("llvm") and - self.get_toml('llvm-config')) or - (module.endswith("jemalloc") and - (self.get_toml('use-jemalloc') == "false" or - self.get_toml('jemalloc'))))] + filtered_submodules = [] + for module in submodules: + if module.endswith("llvm"): + if self.get_toml('llvm-config'): + continue + if module.endswith("llvm-emscripten"): + backends = self.get_toml('codegen-backends') + if backends is None or not 'emscripten' in backends: + continue + if module.endswith("jemalloc"): + if self.get_toml('use-jemalloc') == 'false': + continue + if self.get_toml('jemalloc'): + continue + filtered_submodules.append(module) run(["git", "submodule", "update", - "--init", "--recursive"] + submodules, + "--init", "--recursive"] + filtered_submodules, cwd=self.rust_root, verbose=self.verbose) run(["git", "submodule", "-q", "foreach", "git", "reset", "-q", "--hard"], diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ce30d1f4ce..fcb78c479f 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -26,6 +26,7 @@ use util::{exe, libdir, add_lib_path}; use {Build, Mode}; use cache::{INTERNER, Interned, Cache}; use check; +use test; use flags::Subcommand; use doc; use tool; @@ -94,7 +95,7 @@ pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, pub host: Interned, pub target: Interned, - pub path: Option<&'a Path>, + pub path: PathBuf, } struct StepDescription { @@ -104,6 +105,32 @@ struct StepDescription { only_build: bool, should_run: fn(ShouldRun) -> ShouldRun, make_run: fn(RunConfig), + name: &'static str, +} + +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +struct PathSet { + set: BTreeSet, +} + +impl PathSet { + fn empty() -> PathSet { + PathSet { set: BTreeSet::new() } + } + + fn one>(path: P) -> PathSet { + let mut set = BTreeSet::new(); + set.insert(path.into()); + PathSet { set } + } + + fn has(&self, needle: &Path) -> bool { + self.set.iter().any(|p| p.ends_with(needle)) + } + + fn path(&self, builder: &Builder) -> PathBuf { + self.set.iter().next().unwrap_or(&builder.build.src).to_path_buf() + } } impl StepDescription { @@ -115,10 +142,18 @@ impl StepDescription { only_build: S::ONLY_BUILD, should_run: S::should_run, make_run: S::make_run, + name: unsafe { ::std::intrinsics::type_name::() }, } } - fn maybe_run(&self, builder: &Builder, path: Option<&Path>) { + fn maybe_run(&self, builder: &Builder, pathset: &PathSet) { + if builder.config.exclude.iter().any(|e| pathset.has(e)) { + 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); + } let build = builder.build; let hosts = if self.only_build_targets || self.only_build { build.build_triple() @@ -143,7 +178,7 @@ impl StepDescription { for target in targets { let run = RunConfig { builder, - path, + path: pathset.path(builder), host: *host, target: *target, }; @@ -156,24 +191,33 @@ impl StepDescription { 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); + } + if paths.is_empty() { for (desc, should_run) in v.iter().zip(should_runs) { if desc.default && should_run.is_really_default { - desc.maybe_run(builder, None); + for pathset in &should_run.paths { + desc.maybe_run(builder, pathset); + } } } } else { for path in paths { let mut attempted_run = false; for (desc, should_run) in v.iter().zip(&should_runs) { - if should_run.run(path) { + if let Some(pathset) = should_run.pathset_for_path(path) { attempted_run = true; - desc.maybe_run(builder, Some(path)); + desc.maybe_run(builder, pathset); } } if !attempted_run { - eprintln!("Warning: no rules matched {}.", path.display()); + panic!("Error: no rules matched {}.", path.display()); } } } @@ -184,7 +228,7 @@ impl StepDescription { pub struct ShouldRun<'a> { pub builder: &'a Builder<'a>, // use a BTreeSet to maintain sort order - paths: BTreeSet, + paths: BTreeSet, // If this is a default rule, this is an additional constraint placed on // it's run. Generally something like compiler docs being enabled. @@ -205,31 +249,53 @@ impl<'a> ShouldRun<'a> { self } + // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually + // ever be used, but as we transition to having all rules properly handle passing krate(...) by + // actually doing something different for every crate passed. + pub fn all_krates(mut self, name: &str) -> Self { + let mut set = BTreeSet::new(); + for krate in self.builder.in_tree_crates(name) { + set.insert(PathBuf::from(&krate.path)); + } + self.paths.insert(PathSet { set }); + self + } + pub fn krate(mut self, name: &str) -> Self { - for (_, krate_path) in self.builder.crates(name) { - self.paths.insert(PathBuf::from(krate_path)); + for krate in self.builder.in_tree_crates(name) { + self.paths.insert(PathSet::one(&krate.path)); } self } - pub fn path(mut self, path: &str) -> Self { - self.paths.insert(PathBuf::from(path)); + // single, non-aliased path + pub fn path(self, path: &str) -> Self { + self.paths(&[path]) + } + + // 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 } // allows being more explicit about why should_run in Step returns the value passed to it - pub fn never(self) -> ShouldRun<'a> { + pub fn never(mut self) -> ShouldRun<'a> { + self.paths.insert(PathSet::empty()); self } - fn run(&self, path: &Path) -> bool { - self.paths.iter().any(|p| path.ends_with(p)) + fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> { + self.paths.iter().find(|pathset| pathset.has(path)) } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Kind { Build, + Check, Test, Bench, Dist, @@ -251,18 +317,24 @@ impl<'a> Builder<'a> { tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, native::Llvm, tool::Rustfmt, tool::Miri), - Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest, - check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc, - check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs, - check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri, check::Clippy), - Kind::Bench => describe!(check::Crate, check::CrateLibrustc), + Kind::Check => describe!(check::Std, check::Test, check::Rustc), + 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::RunMake, + test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest, + test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck, + test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme), + Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, - doc::Reference, doc::Rustdoc, doc::CargoBook), + doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook), Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo, - dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign, - dist::DontDistWithMiriEnabled), + 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), } @@ -293,8 +365,10 @@ impl<'a> Builder<'a> { should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); - for path in should_run.paths { - help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + for pathset in should_run.paths { + for path in pathset.set { + help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + } } Some(help) } @@ -302,6 +376,7 @@ impl<'a> Builder<'a> { pub fn run(build: &Build) { let (kind, paths) = match build.config.cmd { Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), + Subcommand::Check { ref paths } => (Kind::Check, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]), @@ -310,6 +385,12 @@ impl<'a> Builder<'a> { Subcommand::Clean { .. } => panic!(), }; + if let Some(path) = paths.get(0) { + if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") { + return; + } + } + let builder = Builder { build, top_stage: build.config.stage.unwrap_or(2), @@ -318,6 +399,12 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), }; + if kind == Kind::Dist { + assert!(!build.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."); + } + StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths); } @@ -357,10 +444,11 @@ impl<'a> Builder<'a> { fn run(self, builder: &Builder) -> Interned { let compiler = self.compiler; - let lib = if compiler.stage >= 2 && builder.build.config.libdir_relative.is_some() { - builder.build.config.libdir_relative.clone().unwrap() + let config = &builder.build.config; + let lib = if compiler.stage >= 1 && config.libdir_relative().is_some() { + builder.build.config.libdir_relative().unwrap() } else { - PathBuf::from("lib") + Path::new("lib") }; let sysroot = builder.sysroot(self.compiler).join(lib) .join("rustlib").join(self.target).join("lib"); @@ -372,6 +460,11 @@ impl<'a> Builder<'a> { self.ensure(Libdir { compiler, target }) } + pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf { + self.sysroot_libdir(compiler, compiler.host) + .with_file_name("codegen-backends") + } + /// Returns the compiler's libdir where it stores the dynamic libraries that /// it itself links against. /// @@ -416,7 +509,7 @@ impl<'a> Builder<'a> { let compiler = self.compiler(self.top_stage, host); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) + .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) .env("RUSTDOC_REAL", self.rustdoc(host)) .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()) @@ -443,7 +536,8 @@ impl<'a> Builder<'a> { let out_dir = self.stage_out(compiler, mode); cargo.env("CARGO_TARGET_DIR", out_dir) .arg(cmd) - .arg("--target").arg(target); + .arg("--target") + .arg(target); // 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. @@ -463,6 +557,18 @@ impl<'a> Builder<'a> { stage = compiler.stage; } + let mut extra_args = env::var(&format!("RUSTFLAGS_STAGE_{}", stage)).unwrap_or_default(); + if stage != 0 { + let s = env::var("RUSTFLAGS_STAGE_NOT_0").unwrap_or_default(); + extra_args.push_str(" "); + extra_args.push_str(&s); + } + + if !extra_args.is_empty() { + cargo.env("RUSTFLAGS", + format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args)); + } + // Customize the compiler we're running. Specify the compiler to cargo // as our shim and then pass it some various options used to configure // how the actual compiler itself is called. @@ -486,9 +592,6 @@ impl<'a> Builder<'a> { }) .env("TEST_MIRI", self.config.test_miri.to_string()) .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); - if let Some(n) = self.config.rust_codegen_units { - cargo.env("RUSTC_CODEGEN_UNITS", n.to_string()); - } if let Some(host_linker) = self.build.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); @@ -496,6 +599,9 @@ impl<'a> Builder<'a> { if let Some(target_linker) = self.build.linker(target) { cargo.env("RUSTC_TARGET_LINKER", target_linker); } + if cmd != "build" && cmd != "check" { + cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build))); + } if mode != Mode::Tool { // Tools don't get debuginfo right now, e.g. cargo and rls don't @@ -547,7 +653,7 @@ impl<'a> Builder<'a> { // build scripts in that situation. // // If LLVM support is disabled we need to use the snapshot compiler to compile - // build scripts, as the new compiler doesnt support executables. + // build scripts, as the new compiler doesn't support executables. if mode == Mode::Libstd || !self.build.config.llvm_enabled { cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); @@ -560,8 +666,7 @@ impl<'a> Builder<'a> { // not guaranteeing correctness across builds if the compiler // is changing under your feet.` if self.config.incremental && compiler.stage == 0 { - let incr_dir = self.incremental_dir(compiler); - cargo.env("RUSTC_INCREMENTAL", incr_dir); + cargo.env("CARGO_INCREMENTAL", "1"); } if let Some(ref on_fail) = self.config.on_fail { @@ -617,9 +722,49 @@ impl<'a> Builder<'a> { // Set this for all builds to make sure doc builds also get it. cargo.env("CFG_RELEASE_CHANNEL", &self.build.config.channel); + // This one's a bit tricky. As of the time of this writing the compiler + // links to the `winapi` crate on crates.io. This crate provides raw + // bindings to Windows system functions, sort of like libc does for + // Unix. This crate also, however, provides "import libraries" for the + // MinGW targets. There's an import library per dll in the windows + // distribution which is what's linked to. These custom import libraries + // are used because the winapi crate can reference Windows functions not + // present in the MinGW import libraries. + // + // For example MinGW may ship libdbghelp.a, but it may not have + // references to all the functions in the dbghelp dll. Instead the + // custom import library for dbghelp in the winapi crates has all this + // information. + // + // Unfortunately for us though the import libraries are linked by + // 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 + // 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 + // our distribution, however, so the link fails. + // + // To solve this problem we tell winapi to not use its bundled import + // libraries. This means that it will link to the system MinGW import + // libraries by default, and the `-ldylib=foo` directives will still get + // passed to the final linker, but they'll look like `-lfoo` which can + // 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. + cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); + if self.is_very_verbose() { cargo.arg("-v"); } + + // This must be kept before the thinlto check, as we set codegen units + // to 1 forcibly there. + if let Some(n) = self.config.rust_codegen_units { + cargo.env("RUSTC_CODEGEN_UNITS", n.to_string()); + } + if self.config.rust_optimize { // FIXME: cargo bench does not accept `--release` if cmd != "bench" { @@ -627,11 +772,17 @@ impl<'a> Builder<'a> { } if self.config.rust_codegen_units.is_none() && - self.build.is_rust_llvm(compiler.host) - { + self.build.is_rust_llvm(compiler.host) && + self.config.rust_thinlto { cargo.env("RUSTC_THINLTO", "1"); + } else if self.config.rust_codegen_units.is_none() { + // Generally, if ThinLTO has been disabled for some reason, we + // want to set the codegen units to 1. However, we shouldn't do + // this if the option was specifically set by the user. + cargo.env("RUSTC_CODEGEN_UNITS", "1"); } } + if self.config.locked_deps { cargo.arg("--locked"); } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index d675834bd6..e412dd9e3e 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.24.1"; +pub const CFG_RELEASE_NUM: &str = "1.25.0"; pub struct GitInfo { inner: Option, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index e4fbae3ff0..767ee4016c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,1497 +8,155 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Implementation of the test-related targets of the build system. -//! -//! This file implements the various regression test suites that we execute on -//! our CI. +//! Implementation of compiling the compiler and standard library, in "check" mode. -use std::collections::HashSet; -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 build_helper::{self, output}; - -use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step}; -use cache::{INTERNER, Interned}; -use compile; -use dist; -use native; -use tool::{self, Tool}; -use util::{self, dylib_path, dylib_path_var}; -use {Build, Mode}; -use toolstate::ToolState; - -const ADB_TEST_DIR: &str = "/data/tmp/work"; - -/// The two modes of the test runner; tests or benchmarks. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] -pub enum TestKind { - /// Run `cargo test` - Test, - /// Run `cargo bench` - Bench, -} - -impl TestKind { - // Return the cargo subcommand for this test kind - fn subcommand(self) -> &'static str { - match self { - TestKind::Test => "test", - TestKind::Bench => "bench", - } - } -} - -impl fmt::Display for TestKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - TestKind::Test => "Testing", - TestKind::Bench => "Benchmarking", - }) - } -} - -fn try_run(build: &Build, cmd: &mut Command) -> bool { - if !build.fail_fast { - if !build.try_run(cmd) { - let mut failures = build.delayed_failures.borrow_mut(); - failures.push(format!("{:?}", cmd)); - return false; - } - } else { - build.run(cmd); - } - true -} - -fn try_run_quiet(build: &Build, cmd: &mut Command) { - if !build.fail_fast { - if !build.try_run_quiet(cmd) { - let mut failures = build.delayed_failures.borrow_mut(); - failures.push(format!("{:?}", cmd)); - } - } else { - build.run_quiet(cmd); - } -} +use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, add_to_sysroot}; +use builder::{RunConfig, Builder, ShouldRun, Step}; +use {Build, Compiler, Mode}; +use cache::Interned; +use std::path::PathBuf; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Linkcheck { - host: Interned, +pub struct Std { + pub target: Interned, } -impl Step for Linkcheck { - type Output = (); - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler. - /// - /// This tool in `src/tools` will verify the validity of all our links in the - /// documentation to ensure we don't have a bunch of dead ones. - fn run(self, builder: &Builder) { - let build = builder.build; - let host = self.host; - - println!("Linkcheck ({})", host); - - builder.default_doc(None); - - let _time = util::timeit(); - try_run(build, builder.tool_cmd(Tool::Linkchecker) - .arg(build.out.join(host).join("doc"))); - } - - fn should_run(run: ShouldRun) -> ShouldRun { - let builder = run.builder; - run.path("src/tools/linkchecker").default_condition(builder.build.config.docs) - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Linkcheck { host: run.target }); - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Cargotest { - stage: u32, - host: Interned, -} - -impl Step for Cargotest { - type Output = (); - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/cargotest") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Cargotest { - stage: run.builder.top_stage, - host: run.target, - }); - } - - /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler. - /// - /// This tool in `src/tools` will check out a few Rust projects and run `cargo - /// test` to ensure that we don't regress the test suites there. - fn run(self, builder: &Builder) { - let build = builder.build; - let compiler = builder.compiler(self.stage, self.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 - // quickly run into path name limit constraints. - let out_dir = build.out.join("ct"); - t!(fs::create_dir_all(&out_dir)); - - let _time = util::timeit(); - let mut cmd = builder.tool_cmd(Tool::CargoTest); - try_run(build, cmd.arg(&build.initial_cargo) - .arg(&out_dir) - .env("RUSTC", builder.rustc(compiler)) - .env("RUSTDOC", builder.rustdoc(compiler.host))); - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Cargo { - stage: u32, - host: Interned, -} - -impl Step for Cargo { - type Output = (); - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/cargo") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Cargo { - stage: run.builder.top_stage, - host: run.target, - }); - } - - /// Runs `cargo test` for `cargo` packaged with Rust. - fn run(self, builder: &Builder) { - let build = builder.build; - 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(build.src.join("src/tools/cargo/Cargo.toml")); - if !build.fail_fast { - cargo.arg("--no-fail-fast"); - } - - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - - // Don't run cross-compile tests, we may not have cross-compiled libstd libs - // available. - cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); - - try_run(build, cargo.env("PATH", &path_for_cargo(builder, compiler))); - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rls { - stage: u32, - host: Interned, -} - -impl Step for Rls { - type Output = (); - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/rls") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Rls { - stage: run.builder.top_stage, - host: run.target, - }); - } - - /// Runs `cargo test` for the rls. - fn run(self, builder: &Builder) { - let build = builder.build; - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - builder.ensure(tool::Rls { compiler, target: self.host }); - let mut cargo = tool::prepare_tool_cargo(builder, - compiler, - host, - "test", - "src/tools/rls"); - - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - - builder.add_rustc_lib_path(compiler, &mut cargo); - - if try_run(build, &mut cargo) { - build.save_toolstate("rls", ToolState::TestPass); - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rustfmt { - stage: u32, - host: Interned, -} - -impl Step for Rustfmt { - type Output = (); - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/rustfmt") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Rustfmt { - stage: run.builder.top_stage, - host: run.target, - }); - } - - /// Runs `cargo test` for rustfmt. - fn run(self, builder: &Builder) { - let build = builder.build; - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - builder.ensure(tool::Rustfmt { compiler, target: self.host }); - let mut cargo = tool::prepare_tool_cargo(builder, - compiler, - host, - "test", - "src/tools/rustfmt"); - - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - - builder.add_rustc_lib_path(compiler, &mut cargo); - - if try_run(build, &mut cargo) { - build.save_toolstate("rustfmt", ToolState::TestPass); - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Miri { - stage: u32, - host: Interned, -} - -impl Step for Miri { - type Output = (); - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - let test_miri = run.builder.build.config.test_miri; - run.path("src/tools/miri").default_condition(test_miri) - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Miri { - stage: run.builder.top_stage, - host: run.target, - }); - } - - /// Runs `cargo test` for miri. - fn run(self, builder: &Builder) { - let build = builder.build; - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - if let Some(miri) = builder.ensure(tool::Miri { compiler, target: self.host }) { - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(build.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"); - // miri tests need to know about the stage sysroot - cargo.env("MIRI_SYSROOT", builder.sysroot(compiler)); - cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); - cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); - cargo.env("MIRI_PATH", miri); - - builder.add_rustc_lib_path(compiler, &mut cargo); - - if try_run(build, &mut cargo) { - build.save_toolstate("miri", ToolState::TestPass); - } - } else { - eprintln!("failed to test miri: could not build"); - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Clippy { - stage: u32, - host: Interned, -} - -impl Step for Clippy { - type Output = (); - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = false; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/clippy") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Clippy { - stage: run.builder.top_stage, - host: run.target, - }); - } - - /// Runs `cargo test` for clippy. - fn run(self, builder: &Builder) { - let build = builder.build; - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - if let Some(clippy) = builder.ensure(tool::Clippy { compiler, target: self.host }) { - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(build.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"); - // clippy tests need to know about the stage sysroot - 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()); - cargo.env("HOST_LIBS", host_libs); - // clippy tests need to find the driver - cargo.env("CLIPPY_DRIVER_PATH", clippy); - - builder.add_rustc_lib_path(compiler, &mut cargo); - - if try_run(build, &mut cargo) { - build.save_toolstate("clippy-driver", ToolState::TestPass); - } - } else { - eprintln!("failed to test clippy: could not build"); - } - } -} - -fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString { - // Configure PATH to find the right rustc. NB. we have to use PATH - // and not RUSTC because the Cargo test suite has tests that will - // fail if rustc is not spelled `rustc`. - let path = builder.sysroot(compiler).join("bin"); - let old_path = env::var_os("PATH").unwrap_or_default(); - env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Tidy { - host: Interned, -} - -impl Step for Tidy { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - const ONLY_BUILD: bool = true; - - /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. - /// - /// This tool in `src/tools` checks up on various bits and pieces of style and - /// otherwise just implements a few lint-like checks that are specific to the - /// compiler itself. - fn run(self, builder: &Builder) { - let build = builder.build; - let host = self.host; - - let _folder = build.fold_output(|| "tidy"); - println!("tidy check ({})", host); - let mut cmd = builder.tool_cmd(Tool::Tidy); - cmd.arg(build.src.join("src")); - if !build.config.vendor { - cmd.arg("--no-vendor"); - } - if build.config.quiet_tests { - cmd.arg("--quiet"); - } - try_run(build, &mut cmd); - } - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/tidy") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Tidy { - host: run.builder.build.build, - }); - } -} - -fn testdir(build: &Build, host: Interned) -> PathBuf { - build.out.join(host).join("test") -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -struct Test { - path: &'static str, - mode: &'static str, - suite: &'static str, -} - -static DEFAULT_COMPILETESTS: &[Test] = &[ - Test { path: "src/test/ui", mode: "ui", suite: "ui" }, - Test { path: "src/test/run-pass", mode: "run-pass", suite: "run-pass" }, - Test { path: "src/test/compile-fail", mode: "compile-fail", suite: "compile-fail" }, - Test { path: "src/test/parse-fail", mode: "parse-fail", suite: "parse-fail" }, - Test { path: "src/test/run-fail", mode: "run-fail", suite: "run-fail" }, - Test { - path: "src/test/run-pass-valgrind", - mode: "run-pass-valgrind", - suite: "run-pass-valgrind" - }, - Test { path: "src/test/mir-opt", mode: "mir-opt", suite: "mir-opt" }, - Test { path: "src/test/codegen", mode: "codegen", suite: "codegen" }, - Test { path: "src/test/codegen-units", mode: "codegen-units", suite: "codegen-units" }, - Test { path: "src/test/incremental", mode: "incremental", suite: "incremental" }, - - // What this runs varies depending on the native platform being apple - Test { path: "src/test/debuginfo", mode: "debuginfo-XXX", suite: "debuginfo" }, -]; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct DefaultCompiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} - -impl Step for DefaultCompiletest { +impl Step for Std { type Output = (); const DEFAULT: bool = true; - fn should_run(mut run: ShouldRun) -> ShouldRun { - for test in DEFAULT_COMPILETESTS { - run = run.path(test.path); - } - run - } - - fn make_run(run: RunConfig) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - - let test = run.path.map(|path| { - DEFAULT_COMPILETESTS.iter().find(|&&test| { - path.ends_with(test.path) - }).unwrap_or_else(|| { - panic!("make_run in compile test to receive test path, received {:?}", path); - }) - }); - - if let Some(test) = test { - run.builder.ensure(DefaultCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite, - }); - } else { - for test in DEFAULT_COMPILETESTS { - run.builder.ensure(DefaultCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite - }); - } - } - } - - fn run(self, builder: &Builder) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: self.mode, - suite: self.suite, - }) - } -} - -// Also default, but host-only. -static HOST_COMPILETESTS: &[Test] = &[ - Test { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" }, - Test { path: "src/test/run-pass-fulldeps", mode: "run-pass", suite: "run-pass-fulldeps" }, - Test { path: "src/test/run-fail-fulldeps", mode: "run-fail", suite: "run-fail-fulldeps" }, - Test { - path: "src/test/compile-fail-fulldeps", - mode: "compile-fail", - suite: "compile-fail-fulldeps", - }, - Test { - path: "src/test/incremental-fulldeps", - mode: "incremental", - suite: "incremental-fulldeps", - }, - Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" }, - Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }, - - Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" }, - Test { path: "src/test/run-pass/pretty", mode: "pretty", suite: "run-pass" }, - Test { path: "src/test/run-fail/pretty", mode: "pretty", suite: "run-fail" }, - Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" }, - Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" }, - Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" }, -]; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct HostCompiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} - -impl Step for HostCompiletest { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(mut run: ShouldRun) -> ShouldRun { - for test in HOST_COMPILETESTS { - run = run.path(test.path); - } - run - } - - fn make_run(run: RunConfig) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - - let test = run.path.map(|path| { - HOST_COMPILETESTS.iter().find(|&&test| { - path.ends_with(test.path) - }).unwrap_or_else(|| { - panic!("make_run in compile test to receive test path, received {:?}", path); - }) - }); - - if let Some(test) = test { - run.builder.ensure(HostCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite, - }); - } else { - for test in HOST_COMPILETESTS { - if test.mode == "pretty" { - continue; - } - run.builder.ensure(HostCompiletest { - compiler, - target: run.target, - mode: test.mode, - suite: test.suite - }); - } - } - } - - fn run(self, builder: &Builder) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: self.mode, - suite: self.suite, - }) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -struct Compiletest { - compiler: Compiler, - target: Interned, - mode: &'static str, - suite: &'static str, -} - -impl Step for Compiletest { - type Output = (); - fn should_run(run: ShouldRun) -> ShouldRun { - run.never() + run.all_krates("std") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Std { + target: run.target, + }); } - /// Executes the `compiletest` tool to run a suite of tests. - /// - /// Compiles all tests with `compiler` for `target` with the specified - /// compiletest `mode` and `suite` arguments. For example `mode` can be - /// "run-pass" or `suite` can be something like `debuginfo`. fn run(self, builder: &Builder) { let build = builder.build; - let compiler = self.compiler; let target = self.target; - let mode = self.mode; - let suite = self.suite; + let compiler = builder.compiler(0, build.build); - // Skip codegen tests if they aren't enabled in configuration. - if !build.config.codegen_tests && suite == "codegen" { - return; - } + let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); + println!("Checking std artifacts ({} -> {})", &compiler.host, target); - if suite == "debuginfo" { - // Skip debuginfo tests on MSVC - if build.build.contains("msvc") { - return; - } - - if mode == "debuginfo-XXX" { - return if build.build.contains("apple") { - builder.ensure(Compiletest { - mode: "debuginfo-lldb", - ..self - }); - } else { - builder.ensure(Compiletest { - mode: "debuginfo-gdb", - ..self - }); - }; - } - - builder.ensure(dist::DebuggerScripts { - sysroot: builder.sysroot(compiler), - 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 == "run-make" { - builder.ensure(compile::Rustc { compiler, target }); - } - - builder.ensure(compile::Test { compiler, target }); - builder.ensure(native::TestHelpers { target }); - builder.ensure(RemoteCopyLibs { compiler, target }); - - let _folder = build.fold_output(|| format!("test_{}", suite)); - println!("Check compiletest suite={} mode={} ({} -> {})", - suite, mode, &compiler.host, target); - let mut cmd = builder.tool_cmd(Tool::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("--rustc-path").arg(builder.rustc(compiler)); - - // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" || mode == "run-make" { - cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); - } - - cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); - cmd.arg("--build-base").arg(testdir(build, 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(build.llvm_filecheck(build.build)); - - if let Some(ref nodejs) = build.config.nodejs { - cmd.arg("--nodejs").arg(nodejs); - } - - let mut flags = vec!["-Crpath".to_string()]; - if build.config.rust_optimize_tests { - flags.push("-O".to_string()); - } - if build.config.rust_debuginfo_tests { - flags.push("-g".to_string()); - } - flags.push("-Zmiri -Zunstable-options".to_string()); - - if let Some(linker) = build.linker(target) { - cmd.arg("--linker").arg(linker); - } - - let hostflags = flags.clone(); - cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); - - let mut targetflags = flags.clone(); - targetflags.push(format!("-Lnative={}", - build.test_helpers_out(target).display())); - cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); - - cmd.arg("--docck-python").arg(build.python()); - - if build.build.ends_with("apple-darwin") { - // Force /usr/bin/python on macOS for LLDB tests because we're loading the - // LLDB plugin's compiled module which only works with the system python - // (namely not Homebrew-installed python) - cmd.arg("--lldb-python").arg("/usr/bin/python"); - } else { - cmd.arg("--lldb-python").arg(build.python()); - } - - if let Some(ref gdb) = build.config.gdb { - cmd.arg("--gdb").arg(gdb); - } - if let Some(ref vers) = build.lldb_version { - cmd.arg("--lldb-version").arg(vers); - } - if let Some(ref dir) = build.lldb_python_dir { - cmd.arg("--lldb-python-dir").arg(dir); - } - - cmd.args(&build.config.cmd.test_args()); - - if build.is_verbose() { - cmd.arg("--verbose"); - } - - if build.config.quiet_tests { - cmd.arg("--quiet"); - } - - if build.config.llvm_enabled { - let llvm_config = build.llvm_config(target); - let llvm_version = output(Command::new(&llvm_config).arg("--version")); - cmd.arg("--llvm-version").arg(llvm_version); - if !build.is_rust_llvm(target) { - cmd.arg("--system-llvm"); - } - - // Only pass correct values for these flags for the `run-make` suite as it - // requires that a C++ compiler was configured which isn't always the case. - if suite == "run-make" { - let llvm_components = output(Command::new(&llvm_config).arg("--components")); - let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); - cmd.arg("--cc").arg(build.cc(target)) - .arg("--cxx").arg(build.cxx(target).unwrap()) - .arg("--cflags").arg(build.cflags(target).join(" ")) - .arg("--llvm-components").arg(llvm_components.trim()) - .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); - if let Some(ar) = build.ar(target) { - cmd.arg("--ar").arg(ar); - } - } - } - if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally dont work without LLVM"); - return; - } - - if suite != "run-make" { - cmd.arg("--cc").arg("") - .arg("--cxx").arg("") - .arg("--cflags").arg("") - .arg("--llvm-components").arg("") - .arg("--llvm-cxxflags").arg(""); - } - - if build.remote_tested(target) { - 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 - // sure to set them here. - // - // Note that if we encounter `PATH` we make sure to append to our own `PATH` - // rather than stomp over it. - if target.contains("msvc") { - for &(ref k, ref v) in build.cc[&target].env() { - if k != "PATH" { - cmd.env(k, v); - } - } - } - cmd.env("RUSTC_BOOTSTRAP", "1"); - build.add_rust_test_threads(&mut cmd); - - if build.config.sanitizers { - cmd.env("SANITIZER_SUPPORT", "1"); - } - - if build.config.profiler { - cmd.env("PROFILER_SUPPORT", "1"); - } - - cmd.arg("--adb-path").arg("adb"); - cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); - if target.contains("android") { - // Assume that cc for this target comes from the android sysroot - cmd.arg("--android-cross-path") - .arg(build.cc(target).parent().unwrap().parent().unwrap()); - } else { - cmd.arg("--android-cross-path").arg(""); - } - - build.ci_env.force_coloring_in_ci(&mut cmd); - - let _time = util::timeit(); - try_run(build, &mut cmd); + let out_dir = build.stage_out(compiler, Mode::Libstd); + build.clear_if_dirty(&out_dir, &builder.rustc(compiler)); + let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check"); + std_cargo(build, &compiler, target, &mut cargo); + run_cargo(build, + &mut cargo, + &libstd_stamp(build, compiler, target), + true); + let libdir = builder.sysroot_libdir(compiler, target); + add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target)); } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Docs { - compiler: Compiler, +pub struct Rustc { + pub target: Interned, } -impl Step for Docs { +impl Step for Rustc { type Output = (); - const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/doc") + run.all_krates("rustc-main") } fn make_run(run: RunConfig) { - run.builder.ensure(Docs { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + run.builder.ensure(Rustc { + target: run.target, }); } - /// Run `rustdoc --test` for all documentation in `src/doc`. + /// Build the compiler. /// - /// This will run all tests in our markdown documentation (e.g. the book) - /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to - /// `compiler`. + /// This will build the compiler for a particular stage of the build using + /// the `compiler` targeting the `target` architecture. The artifacts + /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder) { let build = builder.build; - let compiler = self.compiler; - - 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` - let mut stack = vec![build.src.join("src/doc")]; - let _time = util::timeit(); - let _folder = build.fold_output(|| "test_docs"); - - while let Some(p) = stack.pop() { - if p.is_dir() { - stack.extend(t!(p.read_dir()).map(|p| t!(p).path())); - continue - } - - if p.extension().and_then(|s| s.to_str()) != Some("md") { - continue; - } - - // The nostarch directory in the book is for no starch, and so isn't - // guaranteed to build. We don't care if it doesn't build, so skip it. - if p.to_str().map_or(false, |p| p.contains("nostarch")) { - continue; - } - - markdown_test(builder, compiler, &p); - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct ErrorIndex { - compiler: Compiler, -} - -impl Step for ErrorIndex { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/error_index_generator") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(ErrorIndex { - compiler: run.builder.compiler(run.builder.top_stage, run.host), - }); - } - - /// Run the error index generator tool to execute the tests located in the error - /// index. - /// - /// The `error_index_generator` tool lives in `src/tools` and is used to - /// generate a markdown file from the error indexes of the code base which is - /// then passed to `rustdoc --test`. - fn run(self, builder: &Builder) { - let build = builder.build; - let compiler = self.compiler; - - builder.ensure(compile::Std { compiler, target: compiler.host }); - - let _folder = build.fold_output(|| "test_error_index"); - println!("Testing error-index stage{}", compiler.stage); - - let dir = testdir(build, compiler.host); - t!(fs::create_dir_all(&dir)); - let output = dir.join("error-index.md"); - - let _time = util::timeit(); - build.run(builder.tool_cmd(Tool::ErrorIndex) - .arg("markdown") - .arg(&output) - .env("CFG_BUILD", &build.build) - .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir())); - - markdown_test(builder, compiler, &output); - } -} - -fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) { - let build = builder.build; - let mut file = t!(File::open(markdown)); - let mut contents = String::new(); - t!(file.read_to_string(&mut contents)); - if !contents.contains("```") { - return; - } - - println!("doc tests for: {}", markdown.display()); - let mut cmd = builder.rustdoc_cmd(compiler.host); - build.add_rust_test_threads(&mut cmd); - cmd.arg("--test"); - cmd.arg(markdown); - cmd.env("RUSTC_BOOTSTRAP", "1"); - - let test_args = build.config.cmd.test_args().join(" "); - cmd.arg("--test-args").arg(test_args); - - if build.config.quiet_tests { - try_run_quiet(build, &mut cmd); - } else { - try_run(build, &mut cmd); - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct CrateLibrustc { - compiler: Compiler, - target: Interned, - test_kind: TestKind, - krate: Option>, -} - -impl Step for CrateLibrustc { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.krate("rustc-main") - } - - fn make_run(run: RunConfig) { - let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); - - let make = |name: Option>| { - 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); - }; - - builder.ensure(CrateLibrustc { - compiler, - target: run.target, - test_kind, - krate: name, - }); - }; - - if let Some(path) = run.path { - for (name, krate_path) in builder.crates("rustc-main") { - if path.ends_with(krate_path) { - make(Some(name)); - } - } - } else { - make(None); - } - } - - - fn run(self, builder: &Builder) { - builder.ensure(Crate { - compiler: self.compiler, - target: self.target, - mode: Mode::Librustc, - test_kind: self.test_kind, - krate: self.krate, - }); - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Crate { - compiler: Compiler, - target: Interned, - mode: Mode, - test_kind: TestKind, - krate: Option>, -} - -impl Step for Crate { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.krate("std").krate("test") - } - - fn make_run(run: RunConfig) { - let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); - - let make = |mode: Mode, name: Option>| { - 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); - }; - - builder.ensure(Crate { - compiler, - target: run.target, - mode, - test_kind, - krate: name, - }); - }; - - if let Some(path) = run.path { - for (name, krate_path) in builder.crates("std") { - if path.ends_with(krate_path) { - make(Mode::Libstd, Some(name)); - } - } - for (name, krate_path) in builder.crates("test") { - if path.ends_with(krate_path) { - make(Mode::Libtest, Some(name)); - } - } - } else { - make(Mode::Libstd, None); - make(Mode::Libtest, None); - } - } - - /// Run all unit tests plus documentation tests for an entire crate DAG defined - /// by a `Cargo.toml` - /// - /// This is what runs tests for crates like the standard library, compiler, etc. - /// It essentially is the driver for running `cargo test`. - /// - /// Currently this runs all tests for a DAG by passing a bunch of `-p foo` - /// arguments, and those arguments are discovered from `cargo metadata`. - fn run(self, builder: &Builder) { - let build = builder.build; - let compiler = self.compiler; + let compiler = builder.compiler(0, build.build); let target = self.target; - let mode = self.mode; - let test_kind = self.test_kind; - let krate = self.krate; - builder.ensure(compile::Test { compiler, target }); - builder.ensure(RemoteCopyLibs { compiler, target }); + let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); + println!("Checking compiler artifacts ({} -> {})", &compiler.host, target); - // If we're not doing a full bootstrap but we're testing a stage2 version of - // libstd, then what we're actually testing is the libstd produced in - // stage1. Reflect that here by updating the compiler that we're working - // with automatically. - let compiler = if build.force_use_stage1(compiler, target) { - builder.compiler(1, compiler.host) - } else { - compiler.clone() - }; + let stage_out = builder.stage_out(compiler, Mode::Librustc); + build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target)); + build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); - let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); - let (name, root) = match mode { - Mode::Libstd => { - compile::std_cargo(build, &compiler, target, &mut cargo); - ("libstd", "std") - } - Mode::Libtest => { - compile::test_cargo(build, &compiler, target, &mut cargo); - ("libtest", "test") - } - Mode::Librustc => { - builder.ensure(compile::Rustc { compiler, target }); - compile::rustc_cargo(build, &compiler, target, &mut cargo); - ("librustc", "rustc-main") - } - _ => panic!("can only test libraries"), - }; - let root = INTERNER.intern_string(String::from(root)); - let _folder = build.fold_output(|| { - format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, name) - }); - println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage, - &compiler.host, target); - - // Build up the base `cargo test` command. - // - // Pass in some standard flags then iterate over the graph we've discovered - // in `cargo metadata` with the maps above and figure out what `-p` - // arguments need to get passed. - if test_kind.subcommand() == "test" && !build.fail_fast { - cargo.arg("--no-fail-fast"); - } - - match krate { - Some(krate) => { - cargo.arg("-p").arg(krate); - } - None => { - let mut visited = HashSet::new(); - let mut next = vec![root]; - while let Some(name) = next.pop() { - // Right now jemalloc and the sanitizer crates are - // target-specific crate in the sense that it's not present - // on all platforms. Custom skip it here for now, but if we - // add more this probably wants to get more generalized. - // - // Also skip `build_helper` as it's not compiled normally - // for target during the bootstrap and it's just meant to be - // a helper crate, not tested. If it leaks through then it - // ends up messing with various mtime calculations and such. - if !name.contains("jemalloc") && - *name != *"build_helper" && - !(name.starts_with("rustc_") && name.ends_with("san")) && - name != "dlmalloc" { - cargo.arg("-p").arg(&format!("{}:0.0.0", name)); - } - for dep in build.crates[&name].deps.iter() { - if visited.insert(dep) { - next.push(*dep); - } - } - } - } - } - - // The tests are going to run with the *target* libraries, so we need to - // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent. - // - // Note that to run the compiler we need to run with the *host* libraries, - // but our wrapper scripts arrange for that to be the case anyway. - let mut dylib_path = dylib_path(); - dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target))); - cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); - - cargo.arg("--"); - cargo.args(&build.config.cmd.test_args()); - - if build.config.quiet_tests { - cargo.arg("--quiet"); - } - - let _time = util::timeit(); - - if target.contains("emscripten") { - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - build.config.nodejs.as_ref().expect("nodejs not configured")); - } else if target.starts_with("wasm32") { - // 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 = build.config.nodejs.as_ref() - .expect("nodejs not configured"); - let runner = format!("{} {}/src/etc/wasm32-shim.js", - node.display(), - build.src.display()); - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner); - } else if build.remote_tested(target) { - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - format!("{} run", - builder.tool_exe(Tool::RemoteTestClient).display())); - } - try_run(build, &mut cargo); + let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); + rustc_cargo(build, &mut cargo); + run_cargo(build, + &mut cargo, + &librustc_stamp(build, compiler, target), + true); + let libdir = builder.sysroot_libdir(compiler, target); + add_to_sysroot(&libdir, &librustc_stamp(build, compiler, target)); } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Rustdoc { - host: Interned, - test_kind: TestKind, +pub struct Test { + pub target: Interned, } -impl Step for Rustdoc { +impl Step for Test { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustdoc").path("src/tools/rustdoc") + run.all_krates("test") } 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); - }; - - builder.ensure(Rustdoc { - host: run.host, - test_kind, + run.builder.ensure(Test { + target: run.target, }); } fn run(self, builder: &Builder) { let build = builder.build; - let test_kind = self.test_kind; - - let compiler = builder.compiler(builder.top_stage, self.host); - let target = compiler.host; - - let mut cargo = tool::prepare_tool_cargo(builder, - compiler, - target, - test_kind.subcommand(), - "src/tools/rustdoc"); - let _folder = build.fold_output(|| { - format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) - }); - println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, - &compiler.host, target); - - if test_kind.subcommand() == "test" && !build.fail_fast { - cargo.arg("--no-fail-fast"); - } - - cargo.arg("-p").arg("rustdoc:0.0.0"); - - cargo.arg("--"); - cargo.args(&build.config.cmd.test_args()); - - if build.config.quiet_tests { - cargo.arg("--quiet"); - } - - let _time = util::timeit(); - - try_run(build, &mut cargo); - } -} - -fn envify(s: &str) -> String { - s.chars().map(|c| { - match c { - '-' => '_', - c => c, - } - }).flat_map(|c| c.to_uppercase()).collect() -} - -/// Some test suites are run inside emulators or on remote devices, and most -/// of our test binaries are linked dynamically which means we need to ship -/// the standard library and such to the emulator ahead of time. This step -/// represents this and is a dependency of all test suites. -/// -/// Most of the time this is a noop. For some steps such as shipping data to -/// QEMU we have to build our own tools so we've got conditional dependencies -/// on those programs as well. Note that the remote test client is built for -/// the build target (us) and the server is built for the target. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct RemoteCopyLibs { - compiler: Compiler, - target: Interned, -} - -impl Step for RemoteCopyLibs { - type Output = (); - - fn should_run(run: ShouldRun) -> ShouldRun { - run.never() - } - - fn run(self, builder: &Builder) { - let build = builder.build; - let compiler = self.compiler; let target = self.target; - if !build.remote_tested(target) { - return - } + let compiler = builder.compiler(0, build.build); - builder.ensure(compile::Test { compiler, target }); - - println!("REMOTE copy libs to emulator ({})", target); - t!(fs::create_dir_all(build.out.join("tmp"))); - - let server = builder.ensure(tool::RemoteTestServer { compiler, target }); - - // Spawn the emulator and wait for it to come online - let tool = builder.tool_exe(Tool::RemoteTestClient); - let mut cmd = Command::new(&tool); - cmd.arg("spawn-emulator") - .arg(target) - .arg(&server) - .arg(build.out.join("tmp")); - if let Some(rootfs) = build.qemu_rootfs(target) { - cmd.arg(rootfs); - } - build.run(&mut cmd); - - // Push all our dylibs to the emulator - for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) { - let f = t!(f); - let name = f.file_name().into_string().unwrap(); - if util::is_dylib(&name) { - build.run(Command::new(&tool) - .arg("push") - .arg(f.path())); - } - } + let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); + println!("Checking test artifacts ({} -> {})", &compiler.host, target); + let out_dir = build.stage_out(compiler, Mode::Libtest); + build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); + let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check"); + test_cargo(build, &compiler, target, &mut cargo); + run_cargo(build, + &mut cargo, + &libtest_stamp(build, compiler, target), + true); + let libdir = builder.sysroot_libdir(compiler, target); + add_to_sysroot(&libdir, &libtest_stamp(build, compiler, target)); } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Distcheck; - -impl Step for Distcheck { - type Output = (); - const ONLY_BUILD: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("distcheck") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Distcheck); - } - - /// Run "distcheck", a 'make check' from a tarball - fn run(self, builder: &Builder) { - let build = builder.build; - - println!("Distcheck"); - let dir = build.out.join("tmp").join("distcheck"); - let _ = fs::remove_dir_all(&dir); - t!(fs::create_dir_all(&dir)); - - // Guarantee that these are built before we begin running. - builder.ensure(dist::PlainSourceTarball); - builder.ensure(dist::Src); - - let mut cmd = Command::new("tar"); - cmd.arg("-xzf") - .arg(builder.ensure(dist::PlainSourceTarball)) - .arg("--strip-components=1") - .current_dir(&dir); - build.run(&mut cmd); - build.run(Command::new("./configure") - .args(&build.config.configure_args) - .arg("--enable-vendor") - .current_dir(&dir)); - build.run(Command::new(build_helper::make(&build.build)) - .arg("check") - .current_dir(&dir)); - - // Now make sure that rust-src has all of libstd's dependencies - println!("Distcheck rust-src"); - let dir = build.out.join("tmp").join("distcheck-src"); - let _ = fs::remove_dir_all(&dir); - t!(fs::create_dir_all(&dir)); - - let mut cmd = Command::new("tar"); - cmd.arg("-xzf") - .arg(builder.ensure(dist::Src)) - .arg("--strip-components=1") - .current_dir(&dir); - build.run(&mut cmd); - - let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); - build.run(Command::new(&build.initial_cargo) - .arg("generate-lockfile") - .arg("--manifest-path") - .arg(&toml) - .current_dir(&dir)); - } +/// 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(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { + build.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp") } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Bootstrap; - -impl Step for Bootstrap { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - const ONLY_BUILD: bool = true; - - /// Test the build system itself - fn run(self, builder: &Builder) { - let build = builder.build; - let mut cmd = Command::new(&build.initial_cargo); - cmd.arg("test") - .current_dir(build.src.join("src/bootstrap")) - .env("CARGO_TARGET_DIR", build.out.join("bootstrap")) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTC", &build.initial_rustc); - if !build.fail_fast { - cmd.arg("--no-fail-fast"); - } - cmd.arg("--").args(&build.config.cmd.test_args()); - try_run(build, &mut cmd); - } - - fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/bootstrap") - } - - fn make_run(run: RunConfig) { - run.builder.ensure(Bootstrap); - } +/// Cargo's output path for libtest in a given stage, compiled by a particular +/// compiler for the specified target. +pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { + build.cargo_out(compiler, Mode::Libtest, 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(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp") } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c8e500a4f6..c85b04ddc0 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,7 +48,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libstd").krate("std") + run.all_krates("std") } fn make_run(run: RunConfig) { @@ -80,7 +80,7 @@ impl Step for Std { // Even if we're not building std this stage, the new sysroot must // still contain the musl startup objects. - if target.contains("musl") && !target.contains("mips") { + if target.contains("musl") { let libdir = builder.sysroot_libdir(compiler, target); copy_musl_third_party_objects(build, target, &libdir); } @@ -97,7 +97,7 @@ impl Step for Std { println!("Building stage{} std artifacts ({} -> {})", compiler.stage, &compiler.host, target); - if target.contains("musl") && !target.contains("mips") { + if target.contains("musl") { let libdir = builder.sysroot_libdir(compiler, target); copy_musl_third_party_objects(build, target, &libdir); } @@ -108,7 +108,8 @@ impl Step for Std { std_cargo(build, &compiler, target, &mut cargo); run_cargo(build, &mut cargo, - &libstd_stamp(build, compiler, target)); + &libstd_stamp(build, compiler, target), + false); builder.ensure(StdLink { compiler: builder.compiler(compiler.stage, build.build), @@ -299,7 +300,11 @@ impl Step for StartupObjects { } for obj in ["crt2.o", "dllcrt2.o"].iter() { - copy(&compiler_file(build.cc(target), obj), &sysroot_dir.join(obj)); + let src = compiler_file(build, + build.cc(target), + target, + obj); + copy(&src, &sysroot_dir.join(obj)); } } } @@ -315,7 +320,7 @@ impl Step for Test { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/libtest").krate("test") + run.all_krates("test") } fn make_run(run: RunConfig) { @@ -360,7 +365,8 @@ impl Step for Test { test_cargo(build, &compiler, target, &mut cargo); run_cargo(build, &mut cargo, - &libtest_stamp(build, compiler, target)); + &libtest_stamp(build, compiler, target), + false); builder.ensure(TestLink { compiler: builder.compiler(compiler.stage, build.build), @@ -430,7 +436,7 @@ impl Step for Rustc { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/librustc").krate("rustc-main") + run.all_krates("rustc-main") } fn make_run(run: RunConfig) { @@ -452,10 +458,6 @@ impl Step for Rustc { builder.ensure(Test { compiler, target }); - // Build LLVM for our target. This will implicitly build the host LLVM - // if necessary. - builder.ensure(native::Llvm { target }); - if build.force_use_stage1(compiler, target) { builder.ensure(Rustc { compiler: builder.compiler(1, build.build), @@ -485,10 +487,11 @@ impl Step for Rustc { build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); - rustc_cargo(build, &compiler, target, &mut cargo); + rustc_cargo(build, &mut cargo); run_cargo(build, &mut cargo, - &librustc_stamp(build, compiler, target)); + &librustc_stamp(build, compiler, target), + false); builder.ensure(RustcLink { compiler: builder.compiler(compiler.stage, build.build), @@ -498,15 +501,14 @@ impl Step for Rustc { } } -/// Same as `std_cargo`, but for libtest -pub fn rustc_cargo(build: &Build, - compiler: &Compiler, - target: Interned, - cargo: &mut Command) { +pub fn rustc_cargo(build: &Build, cargo: &mut Command) { cargo.arg("--features").arg(build.rustc_features()) .arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")); + rustc_cargo_env(build, cargo); +} +fn rustc_cargo_env(build: &Build, cargo: &mut Command) { // Set some configuration variables picked up by build scripts and // the compiler alike cargo.env("CFG_RELEASE", build.rust_release()) @@ -514,13 +516,8 @@ pub fn rustc_cargo(build: &Build, .env("CFG_VERSION", build.rust_version()) .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default()); - if compiler.stage == 0 { - cargo.env("CFG_LIBDIR_RELATIVE", "lib"); - } else { - let libdir_relative = - build.config.libdir_relative.clone().unwrap_or(PathBuf::from("lib")); - cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); - } + let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib")); + cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); // If we're not building a compiler with debugging information then remove // these two env vars which would be set otherwise. @@ -538,27 +535,6 @@ pub fn rustc_cargo(build: &Build, if !build.unstable_features() { cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); } - // Flag that rust llvm is in use - if build.is_rust_llvm(target) { - cargo.env("LLVM_RUSTLLVM", "1"); - } - cargo.env("LLVM_CONFIG", build.llvm_config(target)); - let target_config = build.config.target_config.get(&target); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } - // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or macOS - if build.config.llvm_static_stdcpp && - !target.contains("freebsd") && - !target.contains("windows") && - !target.contains("apple") { - cargo.env("LLVM_STATIC_STDCPP", - compiler_file(build.cxx(target).unwrap(), "libstdc++.a")); - } - if build.config.llvm_link_shared { - cargo.env("LLVM_LINK_SHARED", "1"); - } if let Some(ref s) = build.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } @@ -603,6 +579,172 @@ impl Step for RustcLink { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CodegenBackend { + pub compiler: Compiler, + pub target: Interned, + pub backend: Interned, +} + +impl Step for CodegenBackend { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.all_krates("rustc_trans") + } + + fn make_run(run: RunConfig) { + let backend = run.builder.config.rust_codegen_backends.get(0); + let backend = backend.cloned().unwrap_or_else(|| { + INTERNER.intern_str("llvm") + }); + run.builder.ensure(CodegenBackend { + compiler: run.builder.compiler(run.builder.top_stage, run.host), + target: run.target, + backend + }); + } + + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + let target = self.target; + + builder.ensure(Rustc { compiler, target }); + + if build.force_use_stage1(compiler, target) { + builder.ensure(CodegenBackend { + compiler: builder.compiler(1, build.build), + target, + backend: self.backend, + }); + return; + } + + let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + let mut features = build.rustc_features().to_string(); + cargo.arg("--manifest-path") + .arg(build.src.join("src/librustc_trans/Cargo.toml")); + rustc_cargo_env(build, &mut cargo); + + match &*self.backend { + "llvm" | "emscripten" => { + // Build LLVM for our target. This will implicitly build the + // host LLVM if necessary. + let llvm_config = builder.ensure(native::Llvm { + target, + emscripten: self.backend == "emscripten", + }); + + if self.backend == "emscripten" { + features.push_str(" emscripten"); + } + + let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + println!("Building stage{} codegen artifacts ({} -> {}, {})", + compiler.stage, &compiler.host, target, self.backend); + + // Pass down configuration from the LLVM build into the build of + // librustc_llvm and librustc_trans. + if build.is_rust_llvm(target) { + cargo.env("LLVM_RUSTLLVM", "1"); + } + cargo.env("LLVM_CONFIG", &llvm_config); + if self.backend != "emscripten" { + let target_config = build.config.target_config.get(&target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } + } + // Building with a static libstdc++ is only supported on linux right now, + // not for MSVC or macOS + if build.config.llvm_static_stdcpp && + !target.contains("freebsd") && + !target.contains("windows") && + !target.contains("apple") { + let file = compiler_file(build, + build.cxx(target).unwrap(), + target, + "libstdc++.a"); + cargo.env("LLVM_STATIC_STDCPP", file); + } + if build.config.llvm_link_shared { + cargo.env("LLVM_LINK_SHARED", "1"); + } + } + _ => panic!("unknown backend: {}", self.backend), + } + + let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target) + .join(".tmp.stamp"); + let files = run_cargo(build, + cargo.arg("--features").arg(features), + &tmp_stamp, + false); + let mut files = files.into_iter() + .filter(|f| { + let filename = f.file_name().unwrap().to_str().unwrap(); + is_dylib(filename) && filename.contains("rustc_trans-") + }); + let codegen_backend = match files.next() { + Some(f) => f, + None => panic!("no dylibs built for codegen backend?"), + }; + if let Some(f) = files.next() { + panic!("codegen backend built two dylibs:\n{}\n{}", + codegen_backend.display(), + f.display()); + } + let stamp = codegen_backend_stamp(build, compiler, target, self.backend); + let codegen_backend = codegen_backend.to_str().unwrap(); + t!(t!(File::create(&stamp)).write_all(codegen_backend.as_bytes())); + } +} + +/// Creates the `codegen-backends` folder for a compiler that's about to be +/// assembled as a complete compiler. +/// +/// This will take the codegen artifacts produced by `compiler` and link them +/// into an appropriate location for `target_compiler` to be a functional +/// compiler. +fn copy_codegen_backends_to_sysroot(builder: &Builder, + compiler: Compiler, + target_compiler: Compiler) { + let build = builder.build; + let target = target_compiler.host; + + // Note that this step is different than all the other `*Link` steps in + // that it's not assembling a bunch of libraries but rather is primarily + // moving the codegen backend into place. The codegen backend of rustc is + // not linked into the main compiler by default but is rather dynamically + // selected at runtime for inclusion. + // + // Here we're looking for the output dylib of the `CodegenBackend` step and + // we're copying that into the `codegen-backends` folder. + let dst = builder.sysroot_codegen_backends(target_compiler); + t!(fs::create_dir_all(&dst)); + + for backend in builder.config.rust_codegen_backends.iter() { + let stamp = codegen_backend_stamp(build, compiler, target, *backend); + let mut dylib = String::new(); + 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` + let target_filename = { + let dash = filename.find("-").unwrap(); + let dot = filename.find(".").unwrap(); + format!("{}-{}{}", + &filename[..dash], + backend, + &filename[dot..]) + }; + copy(&file, &dst.join(target_filename)); + } +} + /// 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(build: &Build, compiler: Compiler, target: Interned) -> PathBuf { @@ -621,9 +763,22 @@ pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned PathBuf { - let out = output(Command::new(compiler) - .arg(format!("-print-file-name={}", file))); +fn codegen_backend_stamp(build: &Build, + compiler: Compiler, + target: Interned, + backend: Interned) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target) + .join(format!(".librustc_trans-{}.stamp", backend)) +} + +fn compiler_file(build: &Build, + compiler: &Path, + target: Interned, + file: &str) -> PathBuf { + let mut cmd = Command::new(compiler); + cmd.args(build.cflags(target)); + cmd.arg(format!("-print-file-name={}", file)); + let out = output(&mut cmd); PathBuf::from(out.trim()) } @@ -672,7 +827,7 @@ impl Step for Assemble { type Output = Compiler; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/rustc") + run.all_krates("rustc-main") } /// Prepare a new compiler from the artifacts in `stage` @@ -692,20 +847,23 @@ impl Step for Assemble { } // Get the compiler that we'll use to bootstrap ourselves. - let build_compiler = if target_compiler.host != build.build { - // Build a compiler for the host platform. We cannot use the stage0 - // compiler for the host platform for this because it doesn't have - // the libraries we need. FIXME: Perhaps we should download those - // libraries? It would make builds faster... - // FIXME: It may be faster if we build just a stage 1 - // compiler and then use that to bootstrap this compiler - // forward. - builder.compiler(target_compiler.stage - 1, build.build) - } else { - // Build the compiler we'll use to build the stage requested. This - // may build more than one compiler (going down to stage 0). - builder.compiler(target_compiler.stage - 1, target_compiler.host) - }; + // + // Note that this is where the recursive nature of the bootstrap + // happens, as this will request the previous stage's compiler on + // downwards to stage 0. + // + // Also note that we're building a compiler for the host platform. We + // only assume that we can run `build` artifacts, which means that to + // produce some other architecture compiler we need to start from + // `build` to get there. + // + // FIXME: Perhaps we should download those libraries? + // It would make builds faster... + // + // FIXME: It may be faster if we build just a stage 1 compiler and then + // use that to bootstrap this compiler forward. + let build_compiler = + builder.compiler(target_compiler.stage - 1, build.build); // Build the libraries for this compiler to link to (i.e., the libraries // it uses at runtime). NOTE: Crates the target compiler compiles don't @@ -723,7 +881,17 @@ impl Step for Assemble { builder.ensure(RustcLink { compiler, target_compiler, target }); } } else { - builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host }); + builder.ensure(Rustc { + compiler: build_compiler, + target: target_compiler.host, + }); + for &backend in build.config.rust_codegen_backends.iter() { + builder.ensure(CodegenBackend { + compiler: build_compiler, + target: target_compiler.host, + backend, + }); + } } let stage = target_compiler.stage; @@ -742,9 +910,12 @@ impl Step for Assemble { } } - let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host); + copy_codegen_backends_to_sysroot(builder, + build_compiler, + target_compiler); // Link the compiler binary itself into place + let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host); let rustc = out_dir.join(exe("rustc", &*host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); @@ -760,7 +931,7 @@ impl Step for Assemble { /// /// For a particular stage this will link the file listed in `stamp` into the /// `sysroot_dst` provided. -fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) { +pub fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) { t!(fs::create_dir_all(&sysroot_dst)); for path in read_stamp_file(stamp) { copy(&path, &sysroot_dst.join(path.file_name().unwrap())); @@ -790,7 +961,9 @@ fn stderr_isatty() -> bool { } } -fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { +pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) + -> Vec +{ // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. cargo.arg("--message-format").arg("json") @@ -841,7 +1014,8 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { // Skip files like executables if !filename.ends_with(".rlib") && !filename.ends_with(".lib") && - !is_dylib(&filename) { + !is_dylib(&filename) && + !(is_check && filename.ends_with(".rmeta")) { continue } @@ -933,8 +1107,8 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { let mut new_contents = Vec::new(); let mut max = None; let mut max_path = None; - for dep in deps { - let mtime = mtime(&dep); + for dep in deps.iter() { + let mtime = mtime(dep); if Some(mtime) > max { max = Some(mtime); max_path = Some(dep.clone()); @@ -947,7 +1121,7 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { if stamp_contents == new_contents && max <= stamp_mtime { build.verbose(&format!("not updating {:?}; contents equal and {} <= {}", stamp, max, stamp_mtime)); - return + return deps } if max > stamp_mtime { build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); @@ -955,4 +1129,5 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { build.verbose(&format!("updating {:?} as deps changed", stamp)); } t!(t!(File::create(stamp)).write_all(&new_contents)); + deps } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index f3ffe9a276..f3810ac869 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -13,11 +13,11 @@ //! This module implements parsing `config.toml` configuration files to tweak //! how the build runs. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::env; use std::fs::File; use std::io::prelude::*; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process; use std::cmp; @@ -52,9 +52,11 @@ pub struct Config { pub target_config: HashMap, Target>, pub full_bootstrap: bool, pub extended: bool, + pub tools: Option>, pub sanitizers: bool, pub profiler: bool, pub ignore_git: bool, + pub exclude: Vec, pub run_host_only: bool, @@ -81,6 +83,7 @@ pub struct Config { // rust codegen options pub rust_optimize: bool, pub rust_codegen_units: Option, + pub rust_thinlto: bool, pub rust_debug_assertions: bool, pub rust_debuginfo: bool, pub rust_debuginfo_lines: bool, @@ -91,6 +94,7 @@ pub struct Config { pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, pub rust_dist_src: bool, + pub rust_codegen_backends: Vec>, pub build: Interned, pub hosts: Vec>, @@ -106,6 +110,7 @@ pub struct Config { pub debug_jemalloc: bool, pub use_jemalloc: bool, pub backtrace: bool, // support for RUST_BACKTRACE + pub wasm_syscall: bool, // misc pub low_priority: bool, @@ -118,10 +123,10 @@ pub struct Config { pub musl_root: Option, pub prefix: Option, pub sysconfdir: Option, + pub datadir: Option, pub docdir: Option, pub bindir: Option, pub libdir: Option, - pub libdir_relative: Option, pub mandir: Option, pub codegen_tests: bool, pub nodejs: Option, @@ -189,6 +194,7 @@ struct Build { python: Option, full_bootstrap: Option, extended: Option, + tools: Option>, verbose: Option, sanitizers: Option, profiler: Option, @@ -203,13 +209,13 @@ struct Build { struct Install { prefix: Option, sysconfdir: Option, + datadir: Option, docdir: Option, bindir: Option, libdir: Option, mandir: Option, // standard paths, currently unused - datadir: Option, infodir: Option, localstatedir: Option, } @@ -260,6 +266,7 @@ impl Default for StringOrBool { struct Rust { optimize: Option, codegen_units: Option, + thinlto: Option, debug_assertions: Option, debuginfo: Option, debuginfo_lines: Option, @@ -281,6 +288,8 @@ struct Rust { quiet_tests: Option, test_miri: Option, save_toolstates: Option, + codegen_backends: Option>, + wasm_syscall: Option, } /// TOML representation of how each build target is configured. @@ -304,6 +313,7 @@ impl Config { let flags = Flags::parse(&args); let file = flags.config.clone(); let mut config = Config::default(); + config.exclude = flags.exclude; config.llvm_enabled = true; config.llvm_optimize = true; config.llvm_version_check = true; @@ -319,6 +329,7 @@ impl Config { config.ignore_git = false; config.rust_dist_src = true; config.test_miri = false; + config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.on_fail = flags.on_fail; config.stage = flags.stage; @@ -389,6 +400,7 @@ impl Config { set(&mut config.vendor, build.vendor); set(&mut config.full_bootstrap, build.full_bootstrap); set(&mut config.extended, build.extended); + config.tools = build.tools; set(&mut config.verbose, build.verbose); set(&mut config.sanitizers, build.sanitizers); set(&mut config.profiler, build.profiler); @@ -400,6 +412,7 @@ impl Config { if let Some(ref install) = toml.install { config.prefix = install.prefix.clone().map(PathBuf::from); config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from); + config.datadir = install.datadir.clone().map(PathBuf::from); config.docdir = install.docdir.clone().map(PathBuf::from); config.bindir = install.bindir.clone().map(PathBuf::from); config.libdir = install.libdir.clone().map(PathBuf::from); @@ -408,6 +421,7 @@ impl Config { // Store off these values as options because if they're not provided // we'll infer default values for them later + let mut thinlto = None; let mut llvm_assertions = None; let mut debuginfo_lines = None; let mut debuginfo_only_std = None; @@ -451,6 +465,7 @@ impl Config { optimize = rust.optimize; ignore_git = rust.ignore_git; debug_jemalloc = rust.debug_jemalloc; + thinlto = rust.thinlto; set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); @@ -461,11 +476,18 @@ impl Config { set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.quiet_tests, rust.quiet_tests); set(&mut config.test_miri, rust.test_miri); + set(&mut config.wasm_syscall, rust.wasm_syscall); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + if let Some(ref backends) = rust.codegen_backends { + config.rust_codegen_backends = backends.iter() + .map(|s| INTERNER.intern_str(s)) + .collect(); + } + match rust.codegen_units { Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32), Some(n) => config.rust_codegen_units = Some(n), @@ -528,6 +550,7 @@ impl Config { "stable" | "beta" | "nightly" => true, _ => false, }; + config.rust_thinlto = thinlto.unwrap_or(true); config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default); config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default); @@ -543,6 +566,17 @@ impl Config { config } + /// Try to find the relative path of `libdir`. + pub fn libdir_relative(&self) -> Option<&Path> { + let libdir = self.libdir.as_ref()?; + if libdir.is_relative() { + Some(libdir) + } else { + // Try to make it relative to the prefix. + libdir.strip_prefix(self.prefix.as_ref()?).ok() + } + } + pub fn verbose(&self) -> bool { self.verbose > 0 } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 48ca2838e4..99a3ee4e4c 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -65,10 +65,12 @@ o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, m o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball") o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo") o("profiler", "build.profiler", "build the profiler runtime") +o("emscripten", None, "compile the emscripten backend as well as LLVM") # Optimization and debugging options. These may be overridden by the release # channel, etc. o("optimize", "rust.optimize", "build optimized rust code") +o("thinlto", "rust.thinlto", "build Rust with ThinLTO enabled") o("optimize-llvm", "llvm.optimize", "build optimized LLVM") o("llvm-assertions", "llvm.assertions", "build LLVM with assertions") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") @@ -108,6 +110,8 @@ v("musl-root", "target.x86_64-unknown-linux-musl.musl-root", "MUSL root installation directory (deprecated)") v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root", "x86_64-unknown-linux-musl install directory") +v("musl-root-i586", "target.i586-unknown-linux-musl.musl-root", + "i586-unknown-linux-musl install directory") v("musl-root-i686", "target.i686-unknown-linux-musl.musl-root", "i686-unknown-linux-musl install directory") v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root", @@ -118,6 +122,10 @@ v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root", "armv7-unknown-linux-musleabihf install directory") v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root", "aarch64-unknown-linux-musl install directory") +v("musl-root-mips", "target.mips-unknown-linux-musl.musl-root", + "mips-unknown-linux-musl install directory") +v("musl-root-mipsel", "target.mipsel-unknown-linux-musl.musl-root", + "mipsel-unknown-linux-musl install directory") v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs", "rootfs in qemu testing, you probably don't want to use this") v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs", @@ -136,6 +144,7 @@ o("jemalloc", "rust.use-jemalloc", "build liballoc with jemalloc") o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two") o("extended", "build.extended", "build an extended rust tool set") +v("tools", "build.tools", "List of extended tools will be installed") v("build", "build.build", "GNUs ./configure syntax LLVM build triple") v("host", None, "GNUs ./configure syntax LLVM host triples") v("target", None, "GNUs ./configure syntax LLVM target triples") @@ -315,6 +324,8 @@ for key in known_args: set('build.host', value.split(',')) elif option.name == 'target': set('build.target', value.split(',')) + elif option.name == 'emscripten': + set('rust.codegen-backends', ['llvm', 'emscripten']) elif option.name == 'option-checking': # this was handled above pass diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index f011069a70..e7aed7eb4f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -31,6 +31,7 @@ use channel; use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file}; use builder::{Builder, RunConfig, ShouldRun, Step}; use compile; +use native; use tool::{self, Tool}; use cache::{INTERNER, Interned}; use time; @@ -225,6 +226,8 @@ fn make_win_dist( "libwinspool.a", "libws2_32.a", "libwsock32.a", + "libdbghelp.a", + "libmsimg32.a", ]; //Find mingw artifacts we want to bundle @@ -433,6 +436,13 @@ impl Step for Rustc { } } + // Copy over the codegen backends + let backends_src = builder.sysroot_codegen_backends(compiler); + let backends_rel = backends_src.strip_prefix(&src).unwrap(); + let backends_dst = image.join(&backends_rel); + t!(fs::create_dir_all(&backends_dst)); + cp_r(&backends_src, &backends_dst); + // Man pages t!(fs::create_dir_all(image.join("share/man/man1"))); let man_src = build.src.join("src/doc/man"); @@ -579,7 +589,9 @@ impl Step for Std { t!(fs::create_dir_all(&dst)); let mut src = builder.sysroot_libdir(compiler, target).to_path_buf(); src.pop(); // Remove the trailing /lib folder from the sysroot_libdir - cp_r(&src, &dst); + cp_filtered(&src, &dst, &|path| { + path.file_name().and_then(|s| s.to_str()) != Some("codegen-backends") + }); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -887,6 +899,12 @@ impl Step for PlainSourceTarball { .arg("--vers").arg(CARGO_VENDOR_VERSION) .arg("cargo-vendor") .env("RUSTC", &build.initial_rustc); + if let Some(dir) = build.openssl_install_dir(build.config.build) { + builder.ensure(native::Openssl { + target: build.config.build, + }); + cmd.env("OPENSSL_DIR", dir); + } build.run(&mut cmd); } @@ -1215,31 +1233,6 @@ impl Step for Rustfmt { } } - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct DontDistWithMiriEnabled; - -impl Step for DontDistWithMiriEnabled { - type Output = PathBuf; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun) -> ShouldRun { - let build_miri = run.builder.build.config.test_miri; - run.default_condition(build_miri) - } - - fn make_run(run: RunConfig) { - run.builder.ensure(DontDistWithMiriEnabled); - } - - fn run(self, _: &Builder) -> PathBuf { - panic!("Do not distribute with miri enabled.\n\ - The distributed libraries would include all MIR (increasing binary size). - The distributed MIR would include validation statements."); - } -} - - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 832da24c99..55d9723527 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -12,7 +12,7 @@ //! //! This module implements generation for all bits and pieces of documentation //! for the Rust project. This notably includes suites like the rust book, the -//! nomicon, standalone documentation, etc. +//! nomicon, rust by example, standalone documentation, etc. //! //! Everything here is basically just a shim around calling either `rustbook` or //! `rustdoc`. @@ -69,6 +69,7 @@ book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; Rustdoc, "src/doc/rustdoc", "rustdoc"; + RustByExample, "src/doc/rust-by-example", "rust-by-example"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -159,7 +160,7 @@ impl Step for CargoBook { let target = self.target; let name = self.name; - let src = build.src.join("src/tools/cargo/src/doc/book"); + let src = build.src.join("src/tools/cargo/src/doc"); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); @@ -418,8 +419,8 @@ impl Step for Standalone { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { - stage: u32, - target: Interned, + pub stage: u32, + pub target: Interned, } impl Step for Std { @@ -428,7 +429,7 @@ impl Step for Std { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.krate("std").default_condition(builder.build.config.docs) + run.all_krates("std").default_condition(builder.build.config.docs) } fn make_run(run: RunConfig) { @@ -616,7 +617,7 @@ impl Step for Rustc { t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); - compile::rustc_cargo(build, &compiler, target, &mut cargo); + compile::rustc_cargo(build, &mut cargo); if build.config.compiler_docs { // src/rustc/Cargo.toml contains a bin crate called rustc which diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b5d51598fa..42b949527e 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,18 +42,23 @@ pub struct Flags { pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, + pub exclude: Vec, } pub enum Subcommand { Build { paths: Vec, }, + Check { + paths: Vec, + }, Doc { paths: Vec, }, Test { paths: Vec, test_args: Vec, + rustc_args: Vec, fail_fast: bool, }, Bench { @@ -87,6 +92,7 @@ Usage: x.py [options] [...] Subcommands: build Compile either the compiler or libraries + check Compile either the compiler or libraries, using cargo check test Build and run some test suites bench Build and run some benchmarks doc Build documentation @@ -104,6 +110,7 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); + opts.optmulti("", "exclude", "build paths to exclude", "PATH"); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optopt("", "stage", "stage to build", "N"); opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); @@ -127,6 +134,7 @@ To learn more about a subcommand, run `./x.py -h`"); // there on out. let subcommand = args.iter().find(|&s| (s == "build") + || (s == "check") || (s == "test") || (s == "bench") || (s == "doc") @@ -150,6 +158,12 @@ To learn more about a subcommand, run `./x.py -h`"); "test" => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); opts.optmulti("", "test-args", "extra arguments", "ARGS"); + opts.optmulti( + "", + "rustc-args", + "extra options to pass the compiler when running tests", + "ARGS", + ); }, "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, "clean" => { opts.optflag("", "all", "clean all build artifacts"); }, @@ -210,6 +224,21 @@ Arguments: 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."); + } + "check" => { + 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: + + ./x.py check src/libcore + ./x.py check src/libcore src/libproc_macro + + If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note + 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."); } "test" => { subcommand_help.push_str("\n @@ -246,7 +275,10 @@ Arguments: }; // Get any optional paths which occur after the subcommand let cwd = t!(env::current_dir()); - let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); + let src = matches.opt_str("src").map(PathBuf::from) + .or_else(|| env::var_os("SRC").map(PathBuf::from)) + .unwrap_or(cwd.clone()); + 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() { @@ -279,10 +311,14 @@ Arguments: "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"), } } @@ -327,11 +363,6 @@ Arguments: stage = Some(1); } - let cwd = t!(env::current_dir()); - let src = matches.opt_str("src").map(PathBuf::from) - .or_else(|| env::var_os("SRC").map(PathBuf::from)) - .unwrap_or(cwd); - Flags { verbose: matches.opt_count("verbose"), stage, @@ -343,10 +374,12 @@ Arguments: target: split(matches.opt_strs("target")) .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), config: cfg_file, - src, 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::>(), + src, } } } @@ -362,6 +395,15 @@ 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() + } + _ => Vec::new(), + } + } + pub fn fail_fast(&self) -> bool { match *self { Subcommand::Test { fail_fast, .. } => fail_fast, diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 743f32ece9..540c07748b 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -22,6 +22,7 @@ use dist::{self, pkgname, sanitize_sh, tmpdir}; use builder::{Builder, RunConfig, ShouldRun, Step}; use cache::Interned; +use config::Config; pub fn install_docs(builder: &Builder, stage: u32, host: Interned) { install_sh(builder, "docs", "rust-docs", stage, Some(host)); @@ -66,18 +67,21 @@ fn install_sh( let prefix_default = PathBuf::from("/usr/local"); let sysconfdir_default = PathBuf::from("/etc"); - let docdir_default = PathBuf::from("share/doc/rust"); + let datadir_default = PathBuf::from("share"); + let docdir_default = datadir_default.join("doc/rust"); let bindir_default = PathBuf::from("bin"); let libdir_default = PathBuf::from("lib"); - let mandir_default = PathBuf::from("share/man"); + let mandir_default = datadir_default.join("man"); let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default); let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); + let datadir = build.config.datadir.as_ref().unwrap_or(&datadir_default); let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default); let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default); let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default); let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default); let sysconfdir = prefix.join(sysconfdir); + let datadir = prefix.join(datadir); let docdir = prefix.join(docdir); let bindir = prefix.join(bindir); let libdir = prefix.join(libdir); @@ -87,6 +91,7 @@ fn install_sh( let prefix = add_destdir(&prefix, &destdir); let sysconfdir = add_destdir(&sysconfdir, &destdir); + let datadir = add_destdir(&datadir, &destdir); let docdir = add_destdir(&docdir, &destdir); let bindir = add_destdir(&bindir, &destdir); let libdir = add_destdir(&libdir, &destdir); @@ -106,6 +111,7 @@ fn install_sh( .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh"))) .arg(format!("--prefix={}", sanitize_sh(&prefix))) .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir))) + .arg(format!("--datadir={}", sanitize_sh(&datadir))) .arg(format!("--docdir={}", sanitize_sh(&docdir))) .arg(format!("--bindir={}", sanitize_sh(&bindir))) .arg(format!("--libdir={}", sanitize_sh(&libdir))) @@ -144,6 +150,19 @@ macro_rules! install { pub host: Interned, } + impl $name { + #[allow(dead_code)] + fn should_build(config: &Config) -> bool { + config.extended && config.tools.as_ref() + .map_or(true, |t| t.contains($path)) + } + + #[allow(dead_code)] + fn should_install(builder: &Builder) -> bool { + builder.config.tools.as_ref().map_or(false, |t| t.contains($path)) + } + } + impl Step for $name { type Output = (); const DEFAULT: bool = true; @@ -185,32 +204,34 @@ install!((self, builder, _config), install_std(builder, self.stage, *target); } }; - Cargo, "cargo", _config.extended, only_hosts: true, { + Cargo, "cargo", Self::should_build(_config), only_hosts: true, { builder.ensure(dist::Cargo { stage: self.stage, target: self.target }); install_cargo(builder, self.stage, self.target); }; - Rls, "rls", _config.extended, only_hosts: true, { - if builder.ensure(dist::Rls { stage: self.stage, target: self.target }).is_some() { + Rls, "rls", Self::should_build(_config), only_hosts: true, { + if builder.ensure(dist::Rls { stage: self.stage, target: self.target }).is_some() || + Self::should_install(builder) { install_rls(builder, self.stage, self.target); } else { println!("skipping Install RLS stage{} ({})", self.stage, self.target); } }; - Rustfmt, "rustfmt", _config.extended, only_hosts: true, { - if builder.ensure(dist::Rustfmt { stage: self.stage, target: self.target }).is_some() { + Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, { + if builder.ensure(dist::Rustfmt { stage: self.stage, target: self.target }).is_some() || + Self::should_install(builder) { install_rustfmt(builder, self.stage, self.target); } else { println!("skipping Install Rustfmt stage{} ({})", self.stage, self.target); } }; - Analysis, "analysis", _config.extended, only_hosts: false, { + Analysis, "analysis", Self::should_build(_config), only_hosts: false, { builder.ensure(dist::Analysis { compiler: builder.compiler(self.stage, self.host), target: self.target }); install_analysis(builder, self.stage, self.target); }; - Src, "src", _config.extended, only_hosts: true, { + Src, "src", Self::should_build(_config) , only_hosts: true, { builder.ensure(dist::Src); install_src(builder, self.stage); }, ONLY_BUILD; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 52767b403e..afd740ce54 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -113,9 +113,8 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![deny(warnings)] -#![allow(stable_features)] -#![feature(associated_consts)] +//#![deny(warnings)] +#![feature(core_intrinsics)] #[macro_use] extern crate build_helper; @@ -151,6 +150,7 @@ use util::{exe, libdir, OutputFolder, CiEnv}; mod cc_detect; mod channel; mod check; +mod test; mod clean; mod compile; mod metadata; @@ -266,6 +266,18 @@ struct Crate { bench_step: String, } +impl Crate { + fn is_local(&self, build: &Build) -> bool { + self.path.starts_with(&build.config.src) && + !self.path.to_string_lossy().ends_with("_shim") + } + + fn local_path(&self, build: &Build) -> PathBuf { + assert!(self.is_local(build)); + self.path.strip_prefix(&build.config.src).unwrap().into() + } +} + /// The various "modes" of invoking Cargo. /// /// These entries currently correspond to the various output directories of the @@ -423,6 +435,9 @@ impl Build { if self.config.profiler { features.push_str(" profiler"); } + if self.config.wasm_syscall { + features.push_str(" wasm_syscall"); + } features } @@ -432,9 +447,6 @@ impl Build { if self.config.use_jemalloc { features.push_str(" jemalloc"); } - if self.config.llvm_enabled { - features.push_str(" llvm"); - } features } @@ -450,12 +462,6 @@ impl Build { out } - /// Get the directory for incremental by-products when using the - /// given compiler. - fn incremental_dir(&self, compiler: Compiler) -> PathBuf { - self.out.join(&*compiler.host).join(format!("stage{}-incremental", compiler.stage)) - } - /// Returns the root directory for all output generated in a particular /// stage when running with a particular host compiler. /// @@ -489,6 +495,10 @@ impl Build { self.out.join(&*target).join("llvm") } + fn emscripten_llvm_out(&self, target: Interned) -> PathBuf { + self.out.join(&*target).join("llvm-emscripten") + } + /// Output directory for all documentation for a target fn doc_out(&self, target: Interned) -> PathBuf { self.out.join(&*target).join("doc") @@ -667,7 +677,7 @@ impl Build { } } - /// Returns the path to the linker for the given target if it needs to be overriden. + /// Returns the path to the linker for the given target if it needs to be overridden. fn linker(&self, target: Interned) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target) .and_then(|c| c.linker.as_ref()) { @@ -831,7 +841,7 @@ impl Build { ); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); - return n + n } /// Returns the value of `release` above for Rust itself. @@ -950,22 +960,18 @@ impl Build { } } - /// Get a list of crates from a root crate. - /// - /// Returns Vec<(crate, path to crate, is_root_crate)> - fn crates(&self, root: &str) -> Vec<(Interned, &Path)> { - let interned = INTERNER.intern_string(root.to_owned()); + fn in_tree_crates(&self, root: &str) -> Vec<&Crate> { let mut ret = Vec::new(); - let mut list = vec![interned]; + let mut list = vec![INTERNER.intern_str(root)]; let mut visited = HashSet::new(); while let Some(krate) = list.pop() { let krate = &self.crates[&krate]; - // If we can't strip prefix, then out-of-tree path - let path = krate.path.strip_prefix(&self.src).unwrap_or(&krate.path); - ret.push((krate.name, path)); - for dep in &krate.deps { - if visited.insert(dep) && dep != "build_helper" { - list.push(*dep); + if krate.is_local(self) { + ret.push(krate); + for dep in &krate.deps { + if visited.insert(dep) && dep != "build_helper" { + list.push(*dep); + } } } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a5408ee381..3c91cf3ecc 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -22,7 +22,7 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; use std::io::{Read, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::output; @@ -30,7 +30,7 @@ use cmake; use cc; use Build; -use util; +use util::{self, exe}; use build_helper::up_to_date; use builder::{Builder, RunConfig, ShouldRun, Step}; use cache::Interned; @@ -38,35 +38,40 @@ use cache::Interned; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Llvm { pub target: Interned, + pub emscripten: bool, } impl Step for Llvm { - type Output = (); + type Output = PathBuf; // path to llvm-config + const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/llvm") + run.path("src/llvm").path("src/llvm-emscripten") } fn make_run(run: RunConfig) { - run.builder.ensure(Llvm { target: run.target }) + let emscripten = run.path.ends_with("llvm-emscripten"); + run.builder.ensure(Llvm { + target: run.target, + emscripten, + }); } /// Compile LLVM for `target`. - fn run(self, builder: &Builder) { + fn run(self, builder: &Builder) -> PathBuf { let build = builder.build; let target = self.target; - - // If we're not compiling for LLVM bail out here. - if !build.config.llvm_enabled { - return; - } + let emscripten = self.emscripten; // If we're using a custom LLVM bail out here, but we can only use a // custom LLVM for the build triple. - if let Some(config) = build.config.target_config.get(&target) { - if let Some(ref s) = config.llvm_config { - return check_llvm_version(build, s); + if !self.emscripten { + if let Some(config) = build.config.target_config.get(&target) { + if let Some(ref s) = config.llvm_config { + check_llvm_version(build, s); + return s.to_path_buf() + } } } @@ -74,8 +79,17 @@ impl Step for Llvm { let mut rebuild_trigger_contents = String::new(); t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents)); - let out_dir = build.llvm_out(target); + let (out_dir, llvm_config_ret_dir) = if emscripten { + let dir = build.emscripten_llvm_out(target); + let config_dir = dir.join("bin"); + (dir, config_dir) + } else { + (build.llvm_out(target), + build.llvm_out(build.config.build).join("bin")) + }; let done_stamp = out_dir.join("llvm-finished-building"); + let build_llvm_config = llvm_config_ret_dir + .join(exe("llvm-config", &*build.config.build)); if done_stamp.exists() { let mut done_contents = String::new(); t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); @@ -83,17 +97,19 @@ impl Step for Llvm { // If LLVM was already built previously and contents of the rebuild-trigger file // didn't change from the previous build, then no action is required. if done_contents == rebuild_trigger_contents { - return + return build_llvm_config } } let _folder = build.fold_output(|| "llvm"); - println!("Building LLVM for {}", target); + let descriptor = if emscripten { "Emscripten " } else { "" }; + println!("Building {}LLVM for {}", descriptor, target); let _time = util::timeit(); t!(fs::create_dir_all(&out_dir)); // http://llvm.org/docs/CMake.html - let mut cfg = cmake::Config::new(build.src.join("src/llvm")); + let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" }; + let mut cfg = cmake::Config::new(build.src.join(root)); if build.config.ninja { cfg.generator("Ninja"); } @@ -104,13 +120,22 @@ impl Step for Llvm { (true, true) => "RelWithDebInfo", }; - // NOTE: remember to also update `config.toml.example` when changing the defaults! - let llvm_targets = match build.config.llvm_targets { - Some(ref s) => s, - None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon", + // NOTE: remember to also update `config.toml.example` when changing the + // defaults! + let llvm_targets = if self.emscripten { + "JSBackend" + } else { + match build.config.llvm_targets { + Some(ref s) => s, + None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon", + } }; - let llvm_exp_targets = &build.config.llvm_experimental_targets; + let llvm_exp_targets = if self.emscripten { + "" + } else { + &build.config.llvm_experimental_targets[..] + }; let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; @@ -159,8 +184,11 @@ impl Step for Llvm { } // http://llvm.org/docs/HowToCrossCompileLLVM.html - if target != build.build { - builder.ensure(Llvm { target: build.build }); + if target != build.build && !emscripten { + builder.ensure(Llvm { + target: build.build, + emscripten: false, + }); // FIXME: if the llvm root for the build triple is overridden then we // should use llvm-tblgen from there, also should verify that it // actually exists most of the time in normal installs of LLVM. @@ -246,6 +274,8 @@ impl Step for Llvm { cfg.build(); t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes())); + + build_llvm_config } } @@ -429,6 +459,8 @@ impl Step for Openssl { "arm-unknown-linux-gnueabihf" => "linux-armv4", "armv7-linux-androideabi" => "android-armv7", "armv7-unknown-linux-gnueabihf" => "linux-armv4", + "i586-unknown-linux-gnu" => "linux-elf", + "i586-unknown-linux-musl" => "linux-elf", "i686-apple-darwin" => "darwin-i386-cc", "i686-linux-android" => "android-x86", "i686-unknown-freebsd" => "BSD-x86-elf", diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index bc275b7fc7..5184cca653 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -21,9 +21,10 @@ use std::collections::HashMap; use std::env; use std::ffi::{OsString, OsStr}; -use std::fs; -use std::process::Command; +use std::fs::{self, File}; +use std::io::Read; use std::path::PathBuf; +use std::process::Command; use build_helper::output; @@ -169,7 +170,7 @@ pub fn check(build: &mut Build) { } // Make sure musl-root is valid - if target.contains("musl") && !target.contains("mips") { + if target.contains("musl") { // If this is a native target (host is also musl) and no musl-root is given, // fall back to the system toolchain in /usr before giving up if build.musl_root(*target).is_none() && build.config.build == *target { @@ -234,4 +235,14 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake if let Some(ref s) = build.config.ccache { cmd_finder.must_have(s); } + + if build.config.channel == "stable" { + let mut stage0 = String::new(); + t!(t!(File::open(build.src.join("src/stage0.txt"))) + .read_to_string(&mut stage0)); + if stage0.contains("\ndev:") { + panic!("bootstrapping from a dev compiler in a stable release, but \ + should only be bootstrapping from a released compiler!"); + } + } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs new file mode 100644 index 0000000000..64ede4f4ec --- /dev/null +++ b/src/bootstrap/test.rs @@ -0,0 +1,1646 @@ +// 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. + +//! Implementation of the test-related targets of the build system. +//! +//! This file implements the various regression test suites that we execute on +//! our CI. + +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 build_helper::{self, output}; + +use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step}; +use Crate as CargoCrate; +use cache::{INTERNER, Interned}; +use compile; +use dist; +use native; +use tool::{self, Tool}; +use util::{self, dylib_path, dylib_path_var}; +use {Build, Mode}; +use toolstate::ToolState; + +const ADB_TEST_DIR: &str = "/data/tmp/work"; + +/// The two modes of the test runner; tests or benchmarks. +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +pub enum TestKind { + /// Run `cargo test` + Test, + /// Run `cargo bench` + Bench, +} + +impl TestKind { + // Return the cargo subcommand for this test kind + fn subcommand(self) -> &'static str { + match self { + TestKind::Test => "test", + TestKind::Bench => "bench", + } + } +} + +impl fmt::Display for TestKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match *self { + TestKind::Test => "Testing", + TestKind::Bench => "Benchmarking", + }) + } +} + +fn try_run(build: &Build, cmd: &mut Command) -> bool { + if !build.fail_fast { + if !build.try_run(cmd) { + let mut failures = build.delayed_failures.borrow_mut(); + failures.push(format!("{:?}", cmd)); + return false; + } + } else { + build.run(cmd); + } + true +} + +fn try_run_quiet(build: &Build, cmd: &mut Command) { + if !build.fail_fast { + if !build.try_run_quiet(cmd) { + let mut failures = build.delayed_failures.borrow_mut(); + failures.push(format!("{:?}", cmd)); + } + } else { + build.run_quiet(cmd); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Linkcheck { + host: Interned, +} + +impl Step for Linkcheck { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler. + /// + /// This tool in `src/tools` will verify the validity of all our links in the + /// documentation to ensure we don't have a bunch of dead ones. + fn run(self, builder: &Builder) { + let build = builder.build; + let host = self.host; + + println!("Linkcheck ({})", host); + + builder.default_doc(None); + + let _time = util::timeit(); + try_run(build, builder.tool_cmd(Tool::Linkchecker) + .arg(build.out.join(host).join("doc"))); + } + + fn should_run(run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run.path("src/tools/linkchecker").default_condition(builder.build.config.docs) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Linkcheck { host: run.target }); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Cargotest { + stage: u32, + host: Interned, +} + +impl Step for Cargotest { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/cargotest") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Cargotest { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler. + /// + /// This tool in `src/tools` will check out a few Rust projects and run `cargo + /// test` to ensure that we don't regress the test suites there. + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = builder.compiler(self.stage, self.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 + // quickly run into path name limit constraints. + let out_dir = build.out.join("ct"); + t!(fs::create_dir_all(&out_dir)); + + let _time = util::timeit(); + let mut cmd = builder.tool_cmd(Tool::CargoTest); + try_run(build, cmd.arg(&build.initial_cargo) + .arg(&out_dir) + .env("RUSTC", builder.rustc(compiler)) + .env("RUSTDOC", builder.rustdoc(compiler.host))); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Cargo { + stage: u32, + host: Interned, +} + +impl Step for Cargo { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/cargo") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Cargo { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Runs `cargo test` for `cargo` packaged with Rust. + fn run(self, builder: &Builder) { + let build = builder.build; + 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(build.src.join("src/tools/cargo/Cargo.toml")); + if !build.fail_fast { + cargo.arg("--no-fail-fast"); + } + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + // Don't run cross-compile tests, we may not have cross-compiled libstd libs + // available. + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); + + try_run(build, cargo.env("PATH", &path_for_cargo(builder, compiler))); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Rls { + stage: u32, + host: Interned, +} + +impl Step for Rls { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/rls") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Rls { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Runs `cargo test` for the rls. + fn run(self, builder: &Builder) { + let build = builder.build; + let stage = self.stage; + let host = self.host; + let compiler = builder.compiler(stage, host); + + builder.ensure(tool::Rls { compiler, target: self.host }); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + host, + "test", + "src/tools/rls"); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + builder.add_rustc_lib_path(compiler, &mut cargo); + + if try_run(build, &mut cargo) { + build.save_toolstate("rls", ToolState::TestPass); + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Rustfmt { + stage: u32, + host: Interned, +} + +impl Step for Rustfmt { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/rustfmt") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Rustfmt { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Runs `cargo test` for rustfmt. + fn run(self, builder: &Builder) { + let build = builder.build; + let stage = self.stage; + let host = self.host; + let compiler = builder.compiler(stage, host); + + builder.ensure(tool::Rustfmt { compiler, target: self.host }); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + host, + "test", + "src/tools/rustfmt"); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + builder.add_rustc_lib_path(compiler, &mut cargo); + + if try_run(build, &mut cargo) { + build.save_toolstate("rustfmt", ToolState::TestPass); + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Miri { + stage: u32, + host: Interned, +} + +impl Step for Miri { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + let test_miri = run.builder.build.config.test_miri; + run.path("src/tools/miri").default_condition(test_miri) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Miri { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Runs `cargo test` for miri. + fn run(self, builder: &Builder) { + let build = builder.build; + let stage = self.stage; + let host = self.host; + let compiler = builder.compiler(stage, host); + + if let Some(miri) = builder.ensure(tool::Miri { compiler, target: self.host }) { + let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.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"); + // miri tests need to know about the stage sysroot + cargo.env("MIRI_SYSROOT", builder.sysroot(compiler)); + cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); + cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); + cargo.env("MIRI_PATH", miri); + + builder.add_rustc_lib_path(compiler, &mut cargo); + + if try_run(build, &mut cargo) { + build.save_toolstate("miri", ToolState::TestPass); + } + } else { + eprintln!("failed to test miri: could not build"); + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Clippy { + stage: u32, + host: Interned, +} + +impl Step for Clippy { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = false; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/clippy") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Clippy { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Runs `cargo test` for clippy. + fn run(self, builder: &Builder) { + let build = builder.build; + let stage = self.stage; + let host = self.host; + let compiler = builder.compiler(stage, host); + + if let Some(clippy) = builder.ensure(tool::Clippy { compiler, target: self.host }) { + let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.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"); + // clippy tests need to know about the stage sysroot + 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()); + cargo.env("HOST_LIBS", host_libs); + // clippy tests need to find the driver + cargo.env("CLIPPY_DRIVER_PATH", clippy); + + builder.add_rustc_lib_path(compiler, &mut cargo); + + if try_run(build, &mut cargo) { + build.save_toolstate("clippy-driver", ToolState::TestPass); + } + } else { + eprintln!("failed to test clippy: could not build"); + } + } +} + +fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString { + // Configure PATH to find the right rustc. NB. we have to use PATH + // and not RUSTC because the Cargo test suite has tests that will + // fail if rustc is not spelled `rustc`. + let path = builder.sysroot(compiler).join("bin"); + let old_path = env::var_os("PATH").unwrap_or_default(); + env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustdocTheme { + pub compiler: Compiler, +} + +impl Step for RustdocTheme { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/rustdoc-themes") + } + + fn make_run(run: RunConfig) { + let compiler = run.builder.compiler(run.builder.top_stage, run.host); + + run.builder.ensure(RustdocTheme { + compiler: compiler, + }); + } + + fn run(self, builder: &Builder) { + let rustdoc = builder.rustdoc(self.compiler.host); + 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.build.config.channel) + .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) + .env("RUSTDOC_CRATE_VERSION", builder.build.rust_version()) + .env("RUSTC_BOOTSTRAP", "1"); + if let Some(linker) = builder.build.linker(self.compiler.host) { + cmd.env("RUSTC_TARGET_LINKER", linker); + } + try_run(builder.build, &mut cmd); + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustdocJS { + pub host: Interned, + pub target: Interned, +} + +impl Step for RustdocJS { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/test/rustdoc-js") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(RustdocJS { + host: run.host, + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + if let Some(ref nodejs) = builder.config.nodejs { + let mut command = Command::new(nodejs); + command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]); + builder.ensure(::doc::Std { + target: self.target, + stage: builder.top_stage, + }); + builder.run(&mut command); + } else { + println!("No nodejs found, skipping \"src/test/rustdoc-js\" tests"); + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Tidy { + host: Interned, +} + +impl Step for Tidy { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + const ONLY_BUILD: bool = true; + + /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. + /// + /// This tool in `src/tools` checks up on various bits and pieces of style and + /// otherwise just implements a few lint-like checks that are specific to the + /// compiler itself. + fn run(self, builder: &Builder) { + let build = builder.build; + let host = self.host; + + let _folder = build.fold_output(|| "tidy"); + println!("tidy check ({})", host); + let mut cmd = builder.tool_cmd(Tool::Tidy); + cmd.arg(build.src.join("src")); + if !build.config.vendor { + cmd.arg("--no-vendor"); + } + if build.config.quiet_tests { + cmd.arg("--quiet"); + } + try_run(build, &mut cmd); + } + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/tidy") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Tidy { + host: run.builder.build.build, + }); + } +} + +fn testdir(build: &Build, host: Interned) -> PathBuf { + build.out.join(host).join("test") +} + +macro_rules! default_test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { + test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false }); + } +} + +macro_rules! host_test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { + test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true }); + } +} + +macro_rules! test { + ($name:ident { + path: $path:expr, + mode: $mode:expr, + suite: $suite:expr, + default: $default:expr, + host: $host:expr + }) => { + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] + pub struct $name { + pub compiler: Compiler, + pub target: Interned, + } + + impl Step for $name { + type Output = (); + const DEFAULT: bool = $default; + const ONLY_HOSTS: bool = $host; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path($path) + } + + fn make_run(run: RunConfig) { + let compiler = run.builder.compiler(run.builder.top_stage, run.host); + + run.builder.ensure($name { + compiler, + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + builder.ensure(Compiletest { + compiler: self.compiler, + target: self.target, + mode: $mode, + suite: $suite, + }) + } + } + } +} + +default_test!(Ui { + path: "src/test/ui", + mode: "ui", + suite: "ui" +}); + +default_test!(RunPass { + path: "src/test/run-pass", + mode: "run-pass", + suite: "run-pass" +}); + +default_test!(CompileFail { + path: "src/test/compile-fail", + mode: "compile-fail", + suite: "compile-fail" +}); + +default_test!(ParseFail { + path: "src/test/parse-fail", + mode: "parse-fail", + suite: "parse-fail" +}); + +default_test!(RunFail { + path: "src/test/run-fail", + mode: "run-fail", + suite: "run-fail" +}); + +default_test!(RunPassValgrind { + path: "src/test/run-pass-valgrind", + mode: "run-pass-valgrind", + suite: "run-pass-valgrind" +}); + +default_test!(MirOpt { + path: "src/test/mir-opt", + mode: "mir-opt", + suite: "mir-opt" +}); + +default_test!(Codegen { + path: "src/test/codegen", + mode: "codegen", + suite: "codegen" +}); + +default_test!(CodegenUnits { + path: "src/test/codegen-units", + mode: "codegen-units", + suite: "codegen-units" +}); + +default_test!(Incremental { + path: "src/test/incremental", + mode: "incremental", + suite: "incremental" +}); + +default_test!(Debuginfo { + path: "src/test/debuginfo", + // What this runs varies depending on the native platform being apple + mode: "debuginfo-XXX", + suite: "debuginfo" +}); + +host_test!(UiFullDeps { + path: "src/test/ui-fulldeps", + mode: "ui", + suite: "ui-fulldeps" +}); + +host_test!(RunPassFullDeps { + path: "src/test/run-pass-fulldeps", + mode: "run-pass", + suite: "run-pass-fulldeps" +}); + +host_test!(RunFailFullDeps { + path: "src/test/run-fail-fulldeps", + mode: "run-fail", + suite: "run-fail-fulldeps" +}); + +host_test!(CompileFailFullDeps { + path: "src/test/compile-fail-fulldeps", + mode: "compile-fail", + suite: "compile-fail-fulldeps" +}); + +host_test!(IncrementalFullDeps { + path: "src/test/incremental-fulldeps", + mode: "incremental", + suite: "incremental-fulldeps" +}); + +host_test!(Rustdoc { + path: "src/test/rustdoc", + mode: "rustdoc", + suite: "rustdoc" +}); + +test!(Pretty { + path: "src/test/pretty", + mode: "pretty", + suite: "pretty", + default: false, + host: true +}); +test!(RunPassPretty { + path: "src/test/run-pass/pretty", + mode: "pretty", + suite: "run-pass", + default: false, + host: true +}); +test!(RunFailPretty { + path: "src/test/run-fail/pretty", + mode: "pretty", + suite: "run-fail", + default: false, + host: true +}); +test!(RunPassValgrindPretty { + path: "src/test/run-pass-valgrind/pretty", + mode: "pretty", + suite: "run-pass-valgrind", + default: false, + host: true +}); +test!(RunPassFullDepsPretty { + path: "src/test/run-pass-fulldeps/pretty", + mode: "pretty", + suite: "run-pass-fulldeps", + default: false, + host: true +}); +test!(RunFailFullDepsPretty { + path: "src/test/run-fail-fulldeps/pretty", + mode: "pretty", + suite: "run-fail-fulldeps", + default: false, + host: true +}); + +host_test!(RunMake { + path: "src/test/run-make", + mode: "run-make", + suite: "run-make" +}); + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +struct Compiletest { + compiler: Compiler, + target: Interned, + mode: &'static str, + suite: &'static str, +} + +impl Step for Compiletest { + type Output = (); + + fn should_run(run: ShouldRun) -> ShouldRun { + run.never() + } + + /// Executes the `compiletest` tool to run a suite of tests. + /// + /// Compiles all tests with `compiler` for `target` with the specified + /// compiletest `mode` and `suite` arguments. For example `mode` can be + /// "run-pass" or `suite` can be something like `debuginfo`. + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + let target = self.target; + let mode = self.mode; + let suite = self.suite; + + // Skip codegen tests if they aren't enabled in configuration. + if !build.config.codegen_tests && suite == "codegen" { + return; + } + + if suite == "debuginfo" { + // Skip debuginfo tests on MSVC + if build.build.contains("msvc") { + return; + } + + if mode == "debuginfo-XXX" { + return if build.build.contains("apple") { + builder.ensure(Compiletest { + mode: "debuginfo-lldb", + ..self + }); + } else { + builder.ensure(Compiletest { + mode: "debuginfo-gdb", + ..self + }); + }; + } + + builder.ensure(dist::DebuggerScripts { + sysroot: builder.sysroot(compiler), + 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 == "run-make" { + builder.ensure(compile::Rustc { compiler, target }); + } + + builder.ensure(compile::Test { compiler, target }); + builder.ensure(native::TestHelpers { target }); + builder.ensure(RemoteCopyLibs { compiler, target }); + + let _folder = build.fold_output(|| format!("test_{}", suite)); + println!("Check compiletest suite={} mode={} ({} -> {})", + suite, mode, &compiler.host, target); + let mut cmd = builder.tool_cmd(Tool::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("--rustc-path").arg(builder.rustc(compiler)); + + // Avoid depending on rustdoc when we don't need it. + if mode == "rustdoc" || mode == "run-make" { + cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); + } + + cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); + cmd.arg("--build-base").arg(testdir(build, 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(build.llvm_filecheck(build.build)); + + if let Some(ref nodejs) = build.config.nodejs { + cmd.arg("--nodejs").arg(nodejs); + } + + let mut flags = vec!["-Crpath".to_string()]; + if build.config.rust_optimize_tests { + flags.push("-O".to_string()); + } + if build.config.rust_debuginfo_tests { + flags.push("-g".to_string()); + } + flags.push("-Zmiri -Zunstable-options".to_string()); + flags.push(build.config.cmd.rustc_args().join(" ")); + + if let Some(linker) = build.linker(target) { + cmd.arg("--linker").arg(linker); + } + + let hostflags = flags.clone(); + cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); + + let mut targetflags = flags.clone(); + targetflags.push(format!("-Lnative={}", + build.test_helpers_out(target).display())); + cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); + + cmd.arg("--docck-python").arg(build.python()); + + if build.build.ends_with("apple-darwin") { + // Force /usr/bin/python on macOS for LLDB tests because we're loading the + // LLDB plugin's compiled module which only works with the system python + // (namely not Homebrew-installed python) + cmd.arg("--lldb-python").arg("/usr/bin/python"); + } else { + cmd.arg("--lldb-python").arg(build.python()); + } + + if let Some(ref gdb) = build.config.gdb { + cmd.arg("--gdb").arg(gdb); + } + if let Some(ref vers) = build.lldb_version { + cmd.arg("--lldb-version").arg(vers); + } + if let Some(ref dir) = build.lldb_python_dir { + cmd.arg("--lldb-python-dir").arg(dir); + } + + cmd.args(&build.config.cmd.test_args()); + + if build.is_verbose() { + cmd.arg("--verbose"); + } + + if build.config.quiet_tests { + cmd.arg("--quiet"); + } + + if build.config.llvm_enabled { + let llvm_config = build.llvm_config(target); + let llvm_version = output(Command::new(&llvm_config).arg("--version")); + cmd.arg("--llvm-version").arg(llvm_version); + if !build.is_rust_llvm(target) { + cmd.arg("--system-llvm"); + } + + // Only pass correct values for these flags for the `run-make` suite as it + // requires that a C++ compiler was configured which isn't always the case. + if suite == "run-make" { + let llvm_components = output(Command::new(&llvm_config).arg("--components")); + let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); + cmd.arg("--cc").arg(build.cc(target)) + .arg("--cxx").arg(build.cxx(target).unwrap()) + .arg("--cflags").arg(build.cflags(target).join(" ")) + .arg("--llvm-components").arg(llvm_components.trim()) + .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + if let Some(ar) = build.ar(target) { + cmd.arg("--ar").arg(ar); + } + } + } + if suite == "run-make" && !build.config.llvm_enabled { + println!("Ignoring run-make test suite as they generally dont work without LLVM"); + return; + } + + if suite != "run-make" { + cmd.arg("--cc").arg("") + .arg("--cxx").arg("") + .arg("--cflags").arg("") + .arg("--llvm-components").arg("") + .arg("--llvm-cxxflags").arg(""); + } + + if build.remote_tested(target) { + 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 + // sure to set them here. + // + // Note that if we encounter `PATH` we make sure to append to our own `PATH` + // rather than stomp over it. + if target.contains("msvc") { + for &(ref k, ref v) in build.cc[&target].env() { + if k != "PATH" { + cmd.env(k, v); + } + } + } + cmd.env("RUSTC_BOOTSTRAP", "1"); + build.add_rust_test_threads(&mut cmd); + + if build.config.sanitizers { + cmd.env("SANITIZER_SUPPORT", "1"); + } + + if build.config.profiler { + cmd.env("PROFILER_SUPPORT", "1"); + } + + cmd.env("RUST_TEST_TMPDIR", build.out.join("tmp")); + + cmd.arg("--adb-path").arg("adb"); + cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); + if target.contains("android") { + // Assume that cc for this target comes from the android sysroot + cmd.arg("--android-cross-path") + .arg(build.cc(target).parent().unwrap().parent().unwrap()); + } else { + cmd.arg("--android-cross-path").arg(""); + } + + build.ci_env.force_coloring_in_ci(&mut cmd); + + let _time = util::timeit(); + try_run(build, &mut cmd); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Docs { + compiler: Compiler, +} + +impl Step for Docs { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/doc") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Docs { + compiler: run.builder.compiler(run.builder.top_stage, run.host), + }); + } + + /// Run `rustdoc --test` for all documentation in `src/doc`. + /// + /// This will run all tests in our markdown documentation (e.g. the book) + /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to + /// `compiler`. + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + + 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` + let mut stack = vec![build.src.join("src/doc")]; + let _time = util::timeit(); + let _folder = build.fold_output(|| "test_docs"); + + while let Some(p) = stack.pop() { + if p.is_dir() { + stack.extend(t!(p.read_dir()).map(|p| t!(p).path())); + continue + } + + if p.extension().and_then(|s| s.to_str()) != Some("md") { + continue; + } + + // The nostarch directory in the book is for no starch, and so isn't + // guaranteed to build. We don't care if it doesn't build, so skip it. + if p.to_str().map_or(false, |p| p.contains("nostarch")) { + continue; + } + + markdown_test(builder, compiler, &p); + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct ErrorIndex { + compiler: Compiler, +} + +impl Step for ErrorIndex { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/error_index_generator") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(ErrorIndex { + compiler: run.builder.compiler(run.builder.top_stage, run.host), + }); + } + + /// Run the error index generator tool to execute the tests located in the error + /// index. + /// + /// The `error_index_generator` tool lives in `src/tools` and is used to + /// generate a markdown file from the error indexes of the code base which is + /// then passed to `rustdoc --test`. + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + + builder.ensure(compile::Std { compiler, target: compiler.host }); + + let _folder = build.fold_output(|| "test_error_index"); + println!("Testing error-index stage{}", compiler.stage); + + let dir = testdir(build, compiler.host); + t!(fs::create_dir_all(&dir)); + let output = dir.join("error-index.md"); + + let _time = util::timeit(); + build.run(builder.tool_cmd(Tool::ErrorIndex) + .arg("markdown") + .arg(&output) + .env("CFG_BUILD", &build.build) + .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir())); + + markdown_test(builder, compiler, &output); + } +} + +fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) { + let build = builder.build; + let mut file = t!(File::open(markdown)); + let mut contents = String::new(); + t!(file.read_to_string(&mut contents)); + if !contents.contains("```") { + return; + } + + println!("doc tests for: {}", markdown.display()); + let mut cmd = builder.rustdoc_cmd(compiler.host); + build.add_rust_test_threads(&mut cmd); + cmd.arg("--test"); + cmd.arg(markdown); + cmd.env("RUSTC_BOOTSTRAP", "1"); + + let test_args = build.config.cmd.test_args().join(" "); + cmd.arg("--test-args").arg(test_args); + + if build.config.quiet_tests { + try_run_quiet(build, &mut cmd); + } else { + try_run(build, &mut cmd); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CrateLibrustc { + compiler: Compiler, + target: Interned, + test_kind: TestKind, + krate: Interned, +} + +impl Step for CrateLibrustc { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.krate("rustc-main") + } + + fn make_run(run: RunConfig) { + let builder = run.builder; + let compiler = builder.compiler(builder.top_stage, run.host); + + 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); + }; + + builder.ensure(CrateLibrustc { + compiler, + target: run.target, + test_kind, + krate: krate.name, + }); + } + } + } + + fn run(self, builder: &Builder) { + builder.ensure(Crate { + compiler: self.compiler, + target: self.target, + mode: Mode::Librustc, + test_kind: self.test_kind, + krate: self.krate, + }); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CrateNotDefault { + compiler: Compiler, + target: Interned, + test_kind: TestKind, + krate: &'static str, +} + +impl Step for CrateNotDefault { + type Output = (); + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/liballoc_jemalloc") + .path("src/librustc_asan") + .path("src/librustc_lsan") + .path("src/librustc_msan") + .path("src/librustc_tsan") + } + + fn make_run(run: RunConfig) { + 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); + }; + + builder.ensure(CrateNotDefault { + compiler, + target: run.target, + test_kind, + krate: match run.path { + _ if run.path.ends_with("src/liballoc_jemalloc") => "alloc_jemalloc", + _ if run.path.ends_with("src/librustc_asan") => "rustc_asan", + _ if run.path.ends_with("src/librustc_lsan") => "rustc_lsan", + _ if run.path.ends_with("src/librustc_msan") => "rustc_msan", + _ if run.path.ends_with("src/librustc_tsan") => "rustc_tsan", + _ => panic!("unexpected path {:?}", run.path), + }, + }); + } + + fn run(self, builder: &Builder) { + builder.ensure(Crate { + compiler: self.compiler, + target: self.target, + mode: Mode::Libstd, + test_kind: self.test_kind, + krate: INTERNER.intern_str(self.krate), + }); + } +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Crate { + compiler: Compiler, + target: Interned, + mode: Mode, + test_kind: TestKind, + krate: Interned, +} + +impl Step for Crate { + type Output = (); + const DEFAULT: bool = true; + + fn should_run(mut run: ShouldRun) -> ShouldRun { + 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" { + run = run.path(krate.local_path(&builder).to_str().unwrap()); + } + } + run + } + + fn make_run(run: RunConfig) { + let builder = run.builder; + 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); + }; + + builder.ensure(Crate { + compiler, + target: run.target, + mode, + test_kind, + krate: krate.name, + }); + }; + + for krate in builder.in_tree_crates("std") { + if run.path.ends_with(&krate.local_path(&builder)) { + make(Mode::Libstd, krate); + } + } + for krate in builder.in_tree_crates("test") { + if run.path.ends_with(&krate.local_path(&builder)) { + make(Mode::Libtest, krate); + } + } + } + + /// Run all unit tests plus documentation tests for a given crate defined + /// by a `Cargo.toml` (single manifest) + /// + /// This is what runs tests for crates like the standard library, compiler, etc. + /// It essentially is the driver for running `cargo test`. + /// + /// Currently this runs all tests for a DAG by passing a bunch of `-p foo` + /// arguments, and those arguments are discovered from `cargo metadata`. + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + let target = self.target; + let mode = self.mode; + let test_kind = self.test_kind; + let krate = self.krate; + + builder.ensure(compile::Test { compiler, target }); + builder.ensure(RemoteCopyLibs { compiler, target }); + + // If we're not doing a full bootstrap but we're testing a stage2 version of + // libstd, then what we're actually testing is the libstd produced in + // stage1. Reflect that here by updating the compiler that we're working + // with automatically. + let compiler = if build.force_use_stage1(compiler, target) { + builder.compiler(1, compiler.host) + } else { + compiler.clone() + }; + + let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); + match mode { + Mode::Libstd => { + compile::std_cargo(build, &compiler, target, &mut cargo); + } + Mode::Libtest => { + compile::test_cargo(build, &compiler, target, &mut cargo); + } + Mode::Librustc => { + builder.ensure(compile::Rustc { compiler, target }); + compile::rustc_cargo(build, &mut cargo); + } + _ => panic!("can only test libraries"), + }; + let _folder = build.fold_output(|| { + format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) + }); + println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, + &compiler.host, target); + + // Build up the base `cargo test` command. + // + // Pass in some standard flags then iterate over the graph we've discovered + // in `cargo metadata` with the maps above and figure out what `-p` + // arguments need to get passed. + if test_kind.subcommand() == "test" && !build.fail_fast { + cargo.arg("--no-fail-fast"); + } + + cargo.arg("-p").arg(krate); + + // The tests are going to run with the *target* libraries, so we need to + // ensure that those libraries show up in the LD_LIBRARY_PATH equivalent. + // + // Note that to run the compiler we need to run with the *host* libraries, + // but our wrapper scripts arrange for that to be the case anyway. + let mut dylib_path = dylib_path(); + dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target))); + cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + + cargo.arg("--"); + cargo.args(&build.config.cmd.test_args()); + + if build.config.quiet_tests { + cargo.arg("--quiet"); + } + + let _time = util::timeit(); + + if target.contains("emscripten") { + cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + build.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 !build.config.wasm_syscall { + println!("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 = build.config.nodejs.as_ref() + .expect("nodejs not configured"); + let runner = format!("{} {}/src/etc/wasm32-shim.js", + node.display(), + build.src.display()); + cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner); + } else if build.remote_tested(target) { + cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + format!("{} run", + builder.tool_exe(Tool::RemoteTestClient).display())); + } + try_run(build, &mut cargo); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CrateRustdoc { + host: Interned, + test_kind: TestKind, +} + +impl Step for CrateRustdoc { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.paths(&["src/librustdoc", "src/tools/rustdoc"]) + } + + 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); + }; + + builder.ensure(CrateRustdoc { + host: run.host, + test_kind, + }); + } + + fn run(self, builder: &Builder) { + let build = builder.build; + let test_kind = self.test_kind; + + let compiler = builder.compiler(builder.top_stage, self.host); + let target = compiler.host; + + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + target, + test_kind.subcommand(), + "src/tools/rustdoc"); + let _folder = build.fold_output(|| { + format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) + }); + println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, + &compiler.host, target); + + if test_kind.subcommand() == "test" && !build.fail_fast { + cargo.arg("--no-fail-fast"); + } + + cargo.arg("-p").arg("rustdoc:0.0.0"); + + cargo.arg("--"); + cargo.args(&build.config.cmd.test_args()); + + if build.config.quiet_tests { + cargo.arg("--quiet"); + } + + let _time = util::timeit(); + + try_run(build, &mut cargo); + } +} + +fn envify(s: &str) -> String { + s.chars().map(|c| { + match c { + '-' => '_', + c => c, + } + }).flat_map(|c| c.to_uppercase()).collect() +} + +/// Some test suites are run inside emulators or on remote devices, and most +/// of our test binaries are linked dynamically which means we need to ship +/// the standard library and such to the emulator ahead of time. This step +/// represents this and is a dependency of all test suites. +/// +/// Most of the time this is a noop. For some steps such as shipping data to +/// QEMU we have to build our own tools so we've got conditional dependencies +/// on those programs as well. Note that the remote test client is built for +/// the build target (us) and the server is built for the target. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct RemoteCopyLibs { + compiler: Compiler, + target: Interned, +} + +impl Step for RemoteCopyLibs { + type Output = (); + + fn should_run(run: ShouldRun) -> ShouldRun { + run.never() + } + + fn run(self, builder: &Builder) { + let build = builder.build; + let compiler = self.compiler; + let target = self.target; + if !build.remote_tested(target) { + return + } + + builder.ensure(compile::Test { compiler, target }); + + println!("REMOTE copy libs to emulator ({})", target); + t!(fs::create_dir_all(build.out.join("tmp"))); + + let server = builder.ensure(tool::RemoteTestServer { compiler, target }); + + // Spawn the emulator and wait for it to come online + let tool = builder.tool_exe(Tool::RemoteTestClient); + let mut cmd = Command::new(&tool); + cmd.arg("spawn-emulator") + .arg(target) + .arg(&server) + .arg(build.out.join("tmp")); + if let Some(rootfs) = build.qemu_rootfs(target) { + cmd.arg(rootfs); + } + build.run(&mut cmd); + + // Push all our dylibs to the emulator + for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) { + let f = t!(f); + let name = f.file_name().into_string().unwrap(); + if util::is_dylib(&name) { + build.run(Command::new(&tool) + .arg("push") + .arg(f.path())); + } + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Distcheck; + +impl Step for Distcheck { + type Output = (); + const ONLY_BUILD: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("distcheck") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Distcheck); + } + + /// Run "distcheck", a 'make check' from a tarball + fn run(self, builder: &Builder) { + let build = builder.build; + + println!("Distcheck"); + let dir = build.out.join("tmp").join("distcheck"); + let _ = fs::remove_dir_all(&dir); + t!(fs::create_dir_all(&dir)); + + // Guarantee that these are built before we begin running. + builder.ensure(dist::PlainSourceTarball); + builder.ensure(dist::Src); + + let mut cmd = Command::new("tar"); + cmd.arg("-xzf") + .arg(builder.ensure(dist::PlainSourceTarball)) + .arg("--strip-components=1") + .current_dir(&dir); + build.run(&mut cmd); + build.run(Command::new("./configure") + .args(&build.config.configure_args) + .arg("--enable-vendor") + .current_dir(&dir)); + build.run(Command::new(build_helper::make(&build.build)) + .arg("check") + .current_dir(&dir)); + + // Now make sure that rust-src has all of libstd's dependencies + println!("Distcheck rust-src"); + let dir = build.out.join("tmp").join("distcheck-src"); + let _ = fs::remove_dir_all(&dir); + t!(fs::create_dir_all(&dir)); + + let mut cmd = Command::new("tar"); + cmd.arg("-xzf") + .arg(builder.ensure(dist::Src)) + .arg("--strip-components=1") + .current_dir(&dir); + build.run(&mut cmd); + + let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); + build.run(Command::new(&build.initial_cargo) + .arg("generate-lockfile") + .arg("--manifest-path") + .arg(&toml) + .current_dir(&dir)); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Bootstrap; + +impl Step for Bootstrap { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + const ONLY_BUILD: bool = true; + + /// Test the build system itself + fn run(self, builder: &Builder) { + let build = builder.build; + let mut cmd = Command::new(&build.initial_cargo); + cmd.arg("test") + .current_dir(build.src.join("src/bootstrap")) + .env("CARGO_TARGET_DIR", build.out.join("bootstrap")) + .env("RUSTC_BOOTSTRAP", "1") + .env("RUSTC", &build.initial_rustc); + if !build.fail_fast { + cmd.arg("--no-fail-fast"); + } + cmd.arg("--").args(&build.config.cmd.test_args()); + try_run(build, &mut cmd); + } + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/bootstrap") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Bootstrap); + } +} diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index ea055cb5d1..9036eb044b 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -260,6 +260,7 @@ tool!( 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; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 874065f21d..07941e5883 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -315,7 +315,7 @@ pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> { let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = &mut (*db).ReparseTarget as *mut _; + let buf = &mut (*db).ReparseTarget as *mut u16; let mut i = 0; // FIXME: this conversion is very hacky let v = br"\??\"; diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile index 07849a20d0..ff0708459b 100644 --- a/src/ci/docker/asmjs/Dockerfile +++ b/src/ci/docker/asmjs/Dockerfile @@ -29,6 +29,6 @@ ENV EM_CONFIG=/emsdk-portable/.emscripten ENV TARGETS=asmjs-unknown-emscripten -ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-emscripten ENV SCRIPT python2.7 ../x.py test --target $TARGETS diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile similarity index 51% rename from src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile rename to src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile index 2fb1219681..035846b4f6 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -17,14 +17,21 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config WORKDIR /build/ -COPY dist-i586-gnu-i686-musl/musl-libunwind-patch.patch dist-i586-gnu-i686-musl/build-musl.sh /build/ -RUN sh /build/build-musl.sh && rm -rf /build +COPY scripts/musl.sh /build/ +RUN CC=gcc CFLAGS="-m32 -Wa,-mrelax-relocations=no" \ + CXX=g++ CXXFLAGS="-m32 -Wa,-mrelax-relocations=no" \ + bash musl.sh i686 --target=i686 && \ + CC=gcc CFLAGS="-march=pentium -m32 -Wa,-mrelax-relocations=no" \ + CXX=g++ CXXFLAGS="-march=pentium -m32 -Wa,-mrelax-relocations=no" \ + bash musl.sh i586 --target=i586 && \ + rm -rf /build COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS \ --target=i686-unknown-linux-musl,i586-unknown-linux-gnu \ + --musl-root-i586=/musl-i586 \ --musl-root-i686=/musl-i686 \ --enable-extended @@ -35,12 +42,13 @@ ENV RUST_CONFIGURE_ARGS \ # See: https://github.com/rust-lang/rust/issues/34978 ENV CFLAGS_i686_unknown_linux_musl=-Wa,-mrelax-relocations=no ENV CFLAGS_i586_unknown_linux_gnu=-Wa,-mrelax-relocations=no +# FIXME remove -Wl,-melf_i386 after cc is updated to include +# https://github.com/alexcrichton/cc-rs/pull/281 +ENV CFLAGS_i586_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wl,-melf_i386" + +ENV TARGETS=i586-unknown-linux-gnu +ENV TARGETS=$TARGETS,i686-unknown-linux-musl ENV SCRIPT \ - python2.7 ../x.py test \ - --target i686-unknown-linux-musl \ - --target i586-unknown-linux-gnu \ - && \ - python2.7 ../x.py dist \ - --target i686-unknown-linux-musl \ - --target i586-unknown-linux-gnu + python2.7 ../x.py test --target $TARGETS && \ + python2.7 ../x.py dist --target $TARGETS,i586-unknown-linux-musl diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh deleted file mode 100644 index 883859d1fa..0000000000 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh -# 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. - -set -ex - -# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well -export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" -export CXXFLAGS="-Wa,-mrelax-relocations=no" - -MUSL=musl-1.1.17 -curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - -cd $MUSL -CC=gcc \ - CFLAGS="$CFLAGS -m32" \ - ./configure --prefix=/musl-i686 --disable-shared \ - --target=i686 -make AR=ar RANLIB=ranlib -j10 -make install -cd .. - -# To build MUSL we're going to need a libunwind lying around, so acquire that -# here and build it. -curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf - -curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf - - -# Whoa what's this mysterious patch we're applying to libunwind! Why are we -# swapping the values of ESP/EBP in libunwind?! -# -# Discovered in #35599 it turns out that the vanilla build of libunwind is not -# suitable for unwinding 32-bit musl. After some investigation it ended up -# looking like the register values for ESP/EBP were indeed incorrect (swapped) -# in the source. Similar commits in libunwind (r280099 and r282589) have noticed -# this for other platforms, and we just need to realize it for musl linux as -# well. -# -# More technical info can be found at #35599 -cd libunwind-release_37 -patch -Np1 < /build/musl-libunwind-patch.patch -cd .. - -mkdir libunwind-build -cd libunwind-build -CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" cmake ../libunwind-release_37 \ - -DLLVM_PATH=/build/llvm-release_37 \ - -DLIBUNWIND_ENABLE_SHARED=0 -make -j10 -cp lib/libunwind.a /musl-i686/lib diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/musl-libunwind-patch.patch b/src/ci/docker/dist-i586-gnu-i686-musl/musl-libunwind-patch.patch deleted file mode 100644 index 99cd685b72..0000000000 --- a/src/ci/docker/dist-i586-gnu-i686-musl/musl-libunwind-patch.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/include/libunwind.h b/include/libunwind.h -index c5b9633..1360eb2 100644 ---- a/include/libunwind.h -+++ b/include/libunwind.h -@@ -151,8 +151,8 @@ enum { - UNW_X86_ECX = 1, - UNW_X86_EDX = 2, - UNW_X86_EBX = 3, -- UNW_X86_EBP = 4, -- UNW_X86_ESP = 5, -+ UNW_X86_ESP = 4, -+ UNW_X86_EBP = 5, - UNW_X86_ESI = 6, - UNW_X86_EDI = 7 - }; diff --git a/src/ci/docker/dist-i686-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile index 686afc9728..673fa4c0c4 100644 --- a/src/ci/docker/dist-i686-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index a5d776af19..5e405aa72e 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -85,7 +85,9 @@ ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ --enable-extended \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --enable-emscripten \ + --build=i686-unknown-linux-gnu ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs diff --git a/src/ci/docker/dist-i686-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh index 6b991bb59e..08020e533f 100755 --- a/src/ci/docker/dist-i686-linux/build-gcc.sh +++ b/src/ci/docker/dist-i686-linux/build-gcc.sh @@ -17,6 +17,23 @@ 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 diff --git a/src/ci/docker/dist-i686-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh index ff62a68629..aa31f50ba0 100755 --- a/src/ci/docker/dist-i686-linux/build-git.sh +++ b/src/ci/docker/dist-i686-linux/build-git.sh @@ -12,7 +12,7 @@ set -ex source shared.sh -curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - +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 diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index b58ee7a719..c83f101d0a 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -22,22 +22,49 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -WORKDIR /tmp +WORKDIR /build -COPY dist-various-1/build-rumprun.sh /tmp/ +COPY dist-various-1/build-rumprun.sh /build RUN ./build-rumprun.sh -COPY dist-various-1/build-arm-musl.sh /tmp/ -RUN ./build-arm-musl.sh +COPY dist-various-1/install-x86_64-redox.sh /build +RUN ./install-x86_64-redox.sh -COPY dist-various-1/install-mips-musl.sh /tmp/ +COPY dist-various-1/install-mips-musl.sh /build RUN ./install-mips-musl.sh -COPY dist-various-1/install-mipsel-musl.sh /tmp/ +COPY dist-various-1/install-mipsel-musl.sh /build RUN ./install-mipsel-musl.sh -COPY dist-various-1/install-x86_64-redox.sh /tmp/ -RUN ./install-x86_64-redox.sh +# Suppress some warnings in the openwrt toolchains we downloaded +ENV STAGING_DIR=/tmp + +COPY scripts/musl.sh /build +RUN env \ + CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv6 -marm" \ + CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv6 -marm" \ + bash musl.sh arm && \ + env \ + CC=arm-linux-gnueabihf-gcc CFLAGS="-march=armv6 -marm" \ + CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv6 -marm" \ + bash musl.sh armhf && \ + env \ + CC=arm-linux-gnueabihf-gcc CFLAGS="-march=armv7-a" \ + CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv7-a" \ + bash musl.sh armv7 && \ + env \ + CC=aarch64-linux-gnu-gcc \ + CXX=aarch64-linux-gnu-g++ \ + bash musl.sh aarch64 && \ + env \ + CC=mips-openwrt-linux-gcc \ + CXX=mips-openwrt-linux-g++ \ + bash musl.sh mips && \ + env \ + CC=mipsel-openwrt-linux-gcc \ + CXX=mipsel-openwrt-linux-g++ \ + bash musl.sh mipsel && \ + rm -rf /build/* ENV TARGETS=asmjs-unknown-emscripten ENV TARGETS=$TARGETS,wasm32-unknown-emscripten @@ -61,16 +88,16 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \ CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" -# Suppress some warnings in the openwrt toolchains we downloaded -ENV STAGING_DIR=/tmp - ENV RUST_CONFIGURE_ARGS \ - --enable-extended \ --target=$TARGETS \ - --musl-root-arm=/usr/local/arm-linux-musleabi \ - --musl-root-armhf=/usr/local/arm-linux-musleabihf \ - --musl-root-armv7=/usr/local/armv7-linux-musleabihf \ - --musl-root-aarch64=/usr/local/aarch64-linux-musl + --musl-root-arm=/musl-arm \ + --musl-root-armhf=/musl-armhf \ + --musl-root-armv7=/musl-armv7 \ + --musl-root-aarch64=/musl-aarch64 \ + --musl-root-mips=/musl-mips \ + --musl-root-mipsel=/musl-mipsel \ + --enable-emscripten + ENV SCRIPT python2.7 ../x.py dist --target $TARGETS # sccache diff --git a/src/ci/docker/dist-various-1/build-arm-musl.sh b/src/ci/docker/dist-various-1/build-arm-musl.sh deleted file mode 100755 index f9444a35a8..0000000000 --- a/src/ci/docker/dist-various-1/build-arm-musl.sh +++ /dev/null @@ -1,147 +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 - -MUSL=1.1.17 - -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 - rm /tmp/build.log - set -x -} - -curl -O https://www.musl-libc.org/releases/musl-$MUSL.tar.gz -tar xf musl-$MUSL.tar.gz -cd musl-$MUSL -CC=arm-linux-gnueabi-gcc \ -CFLAGS="-march=armv6 -marm" \ - hide_output ./configure \ - --prefix=/usr/local/arm-linux-musleabi \ - --enable-wrapper=gcc -hide_output make -j$(nproc) -hide_output make install -cd .. -rm -rf musl-$MUSL - -tar xf musl-$MUSL.tar.gz -cd musl-$MUSL -CC=arm-linux-gnueabihf-gcc \ -CFLAGS="-march=armv6 -marm" \ - hide_output ./configure \ - --prefix=/usr/local/arm-linux-musleabihf \ - --enable-wrapper=gcc -hide_output make -j$(nproc) -hide_output make install -cd .. -rm -rf musl-$MUSL - -tar xf musl-$MUSL.tar.gz -cd musl-$MUSL -CC=arm-linux-gnueabihf-gcc \ -CFLAGS="-march=armv7-a" \ - hide_output ./configure \ - --prefix=/usr/local/armv7-linux-musleabihf \ - --enable-wrapper=gcc -hide_output make -j$(nproc) -hide_output make install -cd .. -rm -rf musl-$MUSL - -tar xf musl-$MUSL.tar.gz -cd musl-$MUSL -CC=aarch64-linux-gnu-gcc \ -CFLAGS="" \ - hide_output ./configure \ - --prefix=/usr/local/aarch64-linux-musl \ - --enable-wrapper=gcc -hide_output make -j$(nproc) -hide_output make install -cd .. -rm -rf musl-$MUSL* - -ln -nsf ../arm-linux-musleabi/bin/musl-gcc /usr/local/bin/arm-linux-musleabi-gcc -ln -nsf ../arm-linux-musleabihf/bin/musl-gcc /usr/local/bin/arm-linux-musleabihf-gcc -ln -nsf ../armv7-linux-musleabihf/bin/musl-gcc /usr/local/bin/armv7-linux-musleabihf-gcc -ln -nsf ../aarch64-linux-musl/bin/musl-gcc /usr/local/bin/aarch64-unknown-linux-musl-gcc - -curl -L https://github.com/llvm-mirror/llvm/archive/release_39.tar.gz | tar xzf - -curl -L https://github.com/llvm-mirror/libunwind/archive/release_39.tar.gz | tar xzf - - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_39 \ - -DLLVM_PATH=/tmp/llvm-release_39 \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=arm-linux-gnueabi-gcc \ - -DCMAKE_CXX_COMPILER=arm-linux-gnueabi-g++ \ - -DCMAKE_C_FLAGS="-march=armv6 -marm" \ - -DCMAKE_CXX_FLAGS="-march=armv6 -marm" -make -j$(nproc) -cp lib/libunwind.a /usr/local/arm-linux-musleabi/lib -cd .. -rm -rf libunwind-build - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_39 \ - -DLLVM_PATH=/tmp/llvm-release_39 \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \ - -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ \ - -DCMAKE_C_FLAGS="-march=armv6 -marm" \ - -DCMAKE_CXX_FLAGS="-march=armv6 -marm" -make -j$(nproc) -cp lib/libunwind.a /usr/local/arm-linux-musleabihf/lib -cd .. -rm -rf libunwind-build - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_39 \ - -DLLVM_PATH=/tmp/llvm-release_39 \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \ - -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ \ - -DCMAKE_C_FLAGS="-march=armv7-a" \ - -DCMAKE_CXX_FLAGS="-march=armv7-a" -make -j$(nproc) -cp lib/libunwind.a /usr/local/armv7-linux-musleabihf/lib -cd .. -rm -rf libunwind-build - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_39 \ - -DLLVM_PATH=/tmp/llvm-release_39 \ - -DLIBUNWIND_ENABLE_SHARED=0 \ - -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \ - -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \ - -DCMAKE_C_FLAGS="" \ - -DCMAKE_CXX_FLAGS="" -make -j$(nproc) -cp lib/libunwind.a /usr/local/aarch64-linux-musl/lib -cd .. -rm -rf libunwind-build - -rm -rf libunwind-release_39 -rm -rf llvm-release_39 diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index c7885db559..5f342eb570 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:17.10 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh @@ -21,9 +21,12 @@ RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7 RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2-testing main' WORKDIR /tmp -COPY dist-various-2/shared.sh dist-various-2/build-fuchsia-toolchain.sh /tmp/ -COPY dist-various-2/build-solaris-toolchain.sh /tmp/ +COPY dist-various-2/shared.sh /tmp/ +COPY dist-various-2/build-cloudabi-toolchain.sh /tmp/ +RUN /tmp/build-cloudabi-toolchain.sh x86_64-unknown-cloudabi +COPY dist-various-2/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh +COPY dist-various-2/build-solaris-toolchain.sh /tmp/ RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc @@ -50,6 +53,7 @@ ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,x86_64-sun-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 +ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh b/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh new file mode 100755 index 0000000000..8c04d849e8 --- /dev/null +++ b/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# 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. + +set -eux + +# Install prerequisites. +apt-get update +apt-get install -y --no-install-recommends \ + apt-transport-https \ + ca-certificates \ + clang-5.0 \ + cmake \ + curl \ + file \ + g++ \ + gdb \ + git \ + lld-5.0 \ + make \ + python \ + sudo \ + xz-utils + +# Set up a Clang-based cross compiler toolchain. +# Based on the steps described at https://nuxi.nl/cloudabi/debian/ +target=$1 +for tool in ar nm objdump ranlib size; do + ln -s ../lib/llvm-5.0/bin/llvm-${tool} /usr/bin/${target}-${tool} +done +ln -s ../lib/llvm-5.0/bin/clang /usr/bin/${target}-cc +ln -s ../lib/llvm-5.0/bin/clang /usr/bin/${target}-c++ +ln -s ../lib/llvm-5.0/bin/lld /usr/bin/${target}-ld +ln -s ../../${target} /usr/lib/llvm-5.0/${target} + +# Install the C++ runtime libraries from CloudABI Ports. +echo deb https://nuxi.nl/distfiles/cloudabi-ports/debian/ cloudabi cloudabi > \ + /etc/apt/sources.list.d/cloudabi.list +curl 'https://pgp.mit.edu/pks/lookup?op=get&search=0x0DA51B8531344B15' | \ + apt-key add - +apt-get update +apt-get install -y $(echo ${target} | sed -e s/_/-/g)-cxx-runtime diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile index 7483d39562..f9f5b7062f 100644 --- a/src/ci/docker/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index a954fd86a2..d368a00b55 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -85,7 +85,8 @@ ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ --enable-extended \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --enable-emscripten ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs 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 6b991bb59e..08020e533f 100755 --- a/src/ci/docker/dist-x86_64-linux/build-gcc.sh +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -17,6 +17,23 @@ 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 diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh index ff62a68629..aa31f50ba0 100755 --- a/src/ci/docker/dist-x86_64-linux/build-git.sh +++ b/src/ci/docker/dist-x86_64-linux/build-git.sh @@ -12,7 +12,7 @@ set -ex source shared.sh -curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - +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 diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 91ed6bfe1f..c1061309c3 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -17,8 +17,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config WORKDIR /build/ -COPY dist-x86_64-musl/build-musl.sh /build/ -RUN sh /build/build-musl.sh && rm -rf /build + +COPY scripts/musl.sh /build/ +# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well +RUN CC=gcc \ + CFLAGS="-Wa,-mrelax-relocations=no" \ + CXX=g++ \ + CXXFLAGS="-Wa,-mrelax-relocations=no" \ + bash musl.sh x86_64 && rm -rf /build COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh deleted file mode 100644 index 9be8d00114..0000000000 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# 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. - -set -ex - -# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well -export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" -export CXXFLAGS="-Wa,-mrelax-relocations=no" - -MUSL=musl-1.1.17 -curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - -cd $MUSL -./configure --prefix=/musl-x86_64 --disable-shared -make -j10 -make install - -cd .. -rm -rf $MUSL - -# To build MUSL we're going to need a libunwind lying around, so acquire that -# here and build it. -curl -L https://github.com/llvm-mirror/llvm/archive/release_37.tar.gz | tar xzf - -curl -L https://github.com/llvm-mirror/libunwind/archive/release_37.tar.gz | tar xzf - - -mkdir libunwind-build -cd libunwind-build -cmake ../libunwind-release_37 -DLLVM_PATH=/build/llvm-release_37 \ - -DLIBUNWIND_ENABLE_SHARED=0 -make -j10 -cp lib/libunwind.a /musl-x86_64/lib diff --git a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh index 5b4314d57e..e730dd8608 100755 --- a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -54,7 +54,7 @@ cd usr/src # The options, in order, do the following # * this is an unprivileged build # * output to a predictable location -# * disable various uneeded stuff +# * disable various unneeded stuff MKUNPRIVED=yes TOOLDIR=/x-tools/x86_64-unknown-netbsd \ MKSHARE=no MKDOC=no MKHTML=no MKINFO=no MKKMOD=no MKLINT=no MKMAN=no MKNLS=no MKPROFILE=no \ hide_output ./build.sh -j10 -m amd64 tools diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh new file mode 100644 index 0000000000..fb0bd06ce3 --- /dev/null +++ b/src/ci/docker/scripts/musl.sh @@ -0,0 +1,74 @@ +# 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. + +set -ex + +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 + rm /tmp/build.log + set -x +} + +TAG=$1 +shift + +export CFLAGS="-fPIC $CFLAGS" + +MUSL=musl-1.1.18 + +# may have been downloaded in a previous run +if [ ! -d $MUSL ]; then + curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - +fi + +cd $MUSL +./configure --disable-shared --prefix=/musl-$TAG $@ +if [ "$TAG" = "i586" -o "$TAG" = "i686" ]; then + hide_output make -j$(nproc) AR=ar RANLIB=ranlib +else + hide_output make -j$(nproc) +fi +hide_output make install +hide_output make clean + +cd .. + +LLVM=60 + +# may have been downloaded in a previous run +if [ ! -d libunwind-release_$LLVM ]; then + curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf - + curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf - +fi + +mkdir libunwind-build +cd libunwind-build +cmake ../libunwind-release_$LLVM \ + -DLLVM_PATH=/build/llvm-release_$LLVM \ + -DLIBUNWIND_ENABLE_SHARED=0 \ + -DCMAKE_C_COMPILER=$CC \ + -DCMAKE_CXX_COMPILER=$CXX \ + -DCMAKE_C_FLAGS="$CFLAGS" \ + -DCMAKE_CXX_FLAGS="$CXXFLAGS" + +hide_output make -j$(nproc) +cp lib/libunwind.a /musl-$TAG/lib +cd ../ && rm -rf libunwind-build diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index d323677698..7304ed6015 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -19,3 +19,4 @@ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu ENV RUSTFLAGS -Zincremental=/tmp/rust-incr-cache ENV RUST_CHECK_TARGET check +ENV CARGO_INCREMENTAL 0 diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 8ce67518c1..3abf8432cd 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -23,14 +23,15 @@ touch "$TOOLSTATE_FILE" set +e python2.7 "$X_PY" test --no-fail-fast \ src/tools/rls \ - src/tools/rustfmt + src/tools/rustfmt \ + src/tools/clippy set -e cat "$TOOLSTATE_FILE" # If this PR is intended to update one of these tools, do not let the build pass # when they do not test-pass. -for TOOL in rls rustfmt; do +for TOOL in rls rustfmt clippy; do echo "Verifying status of $TOOL..." if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]src/tools/$TOOL$"; then echo "This PR updated 'src/tools/$TOOL', verifying if status is 'test-pass'..." diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 14a1906ff4..8ab4276fa3 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -48,7 +48,12 @@ travis_time_start # Update the cache (a pristine copy of the rust source master) retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ git clone --depth 1 https://github.com/rust-lang/rust.git $cache_src_dir" -(cd $cache_src_dir && git rm src/llvm) +if [ -d $cache_src_dir/src/llvm ]; then + (cd $cache_src_dir && git rm src/llvm) +fi +if [ -d $cache_src_dir/src/llvm-emscripten ]; then + (cd $cache_src_dir && git rm src/llvm-emscripten) +fi retry sh -c "cd $cache_src_dir && \ git submodule deinit -f . && git submodule sync && git submodule update --init" @@ -64,14 +69,14 @@ travis_time_start # http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" for module in $modules; do - if [ "$module" = src/llvm ]; then - commit="$(git ls-tree HEAD src/llvm | awk '{print $3}')" - git rm src/llvm + if [ "$module" = src/llvm ] || [ "$module" = src/llvm-emscripten ]; then + commit="$(git ls-tree HEAD $module | awk '{print $3}')" + git rm $module retry sh -c "rm -f $commit.tar.gz && \ curl -sSL -O https://github.com/rust-lang/llvm/archive/$commit.tar.gz" tar -C src/ -xf "$commit.tar.gz" rm "$commit.tar.gz" - mv "src/llvm-$commit" src/llvm + mv "src/llvm-$commit" $module continue fi if [ ! -e "$cache_src_dir/$module/.git" ]; then diff --git a/src/ci/run.sh b/src/ci/run.sh index b314d5f81a..0ba18a4595 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -46,6 +46,7 @@ export RUST_RELEASE_CHANNEL=stable 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" + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-thinlto" if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" diff --git a/src/dlmalloc/src/dlmalloc.rs b/src/dlmalloc/src/dlmalloc.rs index fba13e69cf..4b780c59de 100644 --- a/src/dlmalloc/src/dlmalloc.rs +++ b/src/dlmalloc/src/dlmalloc.rs @@ -902,7 +902,7 @@ impl Dlmalloc { } // If dv is a better fit, then return null so malloc will use it - if v.is_null() || rsize + size >= self.dvsize { + if v.is_null() || (self.dvsize >= size && !(rsize < self.dvsize - size)) { return ptr::null_mut() } @@ -1512,7 +1512,7 @@ impl Dlmalloc { tsize < self.min_size_for_tree_index(idx + 1)); let mut u = t; - let mut head = ptr::null_mut(); + let mut head = ptr::null_mut::(); loop { let uc = TreeChunk::chunk(u); self.check_any_chunk(uc); diff --git a/src/dlmalloc/src/wasm.rs b/src/dlmalloc/src/wasm.rs index 4655025365..0f86ef5faa 100644 --- a/src/dlmalloc/src/wasm.rs +++ b/src/dlmalloc/src/wasm.rs @@ -1,21 +1,18 @@ use core::ptr; extern { - #[link_name = "llvm.wasm.current.memory.i32"] - fn current_memory() -> u32; - - // TODO: this intrinsic actually returns the previous limit, but LLVM - // doesn't expose that right now. When we upgrade LLVM stop using - // `current_memory` above. #[link_name = "llvm.wasm.grow.memory.i32"] - fn grow_memory(pages: u32); + fn grow_memory(pages: u32) -> i32; } pub unsafe fn alloc(size: usize) -> (*mut u8, usize, u32) { let pages = size / page_size(); - let cur = current_memory() as usize; - grow_memory(pages as u32); - ((cur * page_size()) as *mut u8, pages * page_size(), 0) + let prev = grow_memory(pages as u32); + if prev == -1 { + return (ptr::null_mut(), 0, 0); + } + let prev = prev as usize; + ((prev * page_size()) as *mut u8, pages * page_size(), 0) } pub unsafe fn remap(_ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) diff --git a/src/doc/README.md b/src/doc/README.md index e1d95732b4..5f25894afd 100644 --- a/src/doc/README.md +++ b/src/doc/README.md @@ -29,4 +29,4 @@ rustdoc reference.md An overview of how to use the `rustdoc` command is available [in the docs][1]. Further details are available from the command line by with `rustdoc --help`. -[1]: https://github.com/rust-lang/rust/blob/master/src/doc/book/documentation.md +[1]: https://github.com/rust-lang/rust/blob/master/src/doc/rustdoc/src/what-is-rustdoc.md diff --git a/src/doc/book/.travis.yml b/src/doc/book/.travis.yml index 9d0041adf2..7977d19f41 100644 --- a/src/doc/book/.travis.yml +++ b/src/doc/book/.travis.yml @@ -13,6 +13,6 @@ addons: - aspell - aspell-en before_script: - - (cargo install mdbook --vers 0.0.26 --force || true) + - (cargo install mdbook --vers 0.1.0 --force || true) script: - bash ci/build.sh diff --git a/src/doc/book/README.md b/src/doc/book/README.md index ef1408c838..d7d5f28264 100644 --- a/src/doc/book/README.md +++ b/src/doc/book/README.md @@ -1,7 +1,7 @@ # NOTICE ABOUT STATUS The second edition of The Rust Programming Language is getting ever closer to being printed! -This means we're not able to make large changes to chapters that are in any column to the +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 our Project board][proj]. Issues or pull requests submitted for frozen chapters are welcome but will be closed until we start work on a third edition. Thank you! @@ -12,22 +12,18 @@ on a third edition. Thank you! [![Build Status](https://travis-ci.org/rust-lang/book.svg?branch=master)](https://travis-ci.org/rust-lang/book) -This repo contains two editions of “The Rust Programming Languageâ€. +This repo contains two editions of “The Rust Programming Languageâ€; we +recommend starting with the second edition. -The second edition is a rewrite that will be printed by NoStarch Press, -available around October 2017. +The second edition is a rewrite that will be printed by No Starch Press, +available around May 2018. Check [the No Starch Page][nostarch] for the latest +information on the release date and how to order. -[You can read the very latest online][html]; the last few chapters aren't completed yet, but -the first half of the book is much improved from the first edition. We recommend -starting with the second edition. +[nostarch]: https://nostarch.com/rust -[html]: http://rust-lang.github.io/book/ - -Note that links to the standard library won't work in this version; this is intentional -so that links work with the book and API docs shipped with Rust installations for offline -reading. For a version of the book where these links do work, please see the book as shipped -with the latest [stable], [beta], or [nightly] Rust releases. Be aware that issues in those -versions may have been fixed in this repository already. +You can read the book for free online! Please see the book as shipped with the +latest [stable], [beta], or [nightly] Rust releases. Be aware that issues in +those versions may have been fixed in this repository already. [stable]: https://doc.rust-lang.org/stable/book/second-edition/ [beta]: https://doc.rust-lang.org/beta/book/second-edition/ diff --git a/src/doc/book/first-edition/book.toml b/src/doc/book/first-edition/book.toml index f3ae80a39d..3a3189c4d7 100644 --- a/src/doc/book/first-edition/book.toml +++ b/src/doc/book/first-edition/book.toml @@ -1,2 +1,3 @@ +[book] title = "The Rust Programming Language" author = "The Rust Project Developers" diff --git a/src/doc/book/first-edition/src/choosing-your-guarantees.md b/src/doc/book/first-edition/src/choosing-your-guarantees.md index b1ba4df24c..4e69c8bdba 100644 --- a/src/doc/book/first-edition/src/choosing-your-guarantees.md +++ b/src/doc/book/first-edition/src/choosing-your-guarantees.md @@ -4,8 +4,8 @@ One important feature of Rust is that it lets us control the costs and guarantee of a program. There are various “wrapper type” abstractions in the Rust standard library which embody -a multitude of tradeoffs between cost, ergonomics, and guarantees. Many let one choose between -run time and compile time enforcement. This section will explain a few selected abstractions in +a multitude of trade-offs between cost, ergonomics, and guarantees. Many let one choose between +run-time and compile-time enforcement. This section will explain a few selected abstractions in detail. Before proceeding, it is highly recommended that one reads about [ownership][ownership] and @@ -86,7 +86,7 @@ last. It's a viable alternative to `&T` when `&T` is either impossible to static correctness, or creates extremely unergonomic code where the programmer does not wish to spend the development cost of working with. -This pointer is _not_ thread safe, and Rust will not let it be sent or shared with other threads. +This pointer is _not_ thread-safe, and Rust will not let it be sent or shared with other threads. This lets one avoid the cost of atomics in situations where they are unnecessary. There is a sister smart pointer to this one, `Weak`. This is a non-owning, but also non-borrowed, @@ -243,7 +243,7 @@ At runtime each borrow causes a modification/check of the refcount. Many of the types above cannot be used in a threadsafe manner. Particularly, `Rc` and `RefCell`, which both use non-atomic reference counts (_atomic_ reference counts are those which can be incremented from multiple threads without causing a data race), cannot be used this way. This -makes them cheaper to use, but we need thread safe versions of these too. They exist, in the form of +makes them cheaper to use, but we need thread-safe versions of these too. They exist, in the form of `Arc` and `Mutex`/`RwLock` Note that the non-threadsafe types _cannot_ be sent between threads, and this is checked at compile @@ -271,7 +271,7 @@ behavior, so even monotonicity may not be enough to justify `UnsafeCell`. #### Guarantees -Like `Rc`, this provides the (thread safe) guarantee that the destructor for the internal data will +Like `Rc`, this provides the (thread-safe) guarantee that the destructor for the internal data will be run when the last `Arc` goes out of scope (barring any cycles). #### Cost @@ -354,7 +354,7 @@ When reading code that uses these, go in step by step and look at the guarantees When choosing a composed type, we must do the reverse; figure out which guarantees we want, and at which point of the composition we need them. For example, if there is a choice between -`Vec>` and `RefCell>`, we should figure out the tradeoffs as done above and pick +`Vec>` and `RefCell>`, we should figure out the trade-offs as done above and pick one. [^3]: `&[T]` and `&mut [T]` are _slices_; they consist of a pointer and a length and can refer to a portion of a vector or array. `&mut [T]` can have its elements mutated, however its length cannot be touched. diff --git a/src/doc/book/first-edition/src/concurrency.md b/src/doc/book/first-edition/src/concurrency.md index 0fd71ee6d1..a8af9cad77 100644 --- a/src/doc/book/first-edition/src/concurrency.md +++ b/src/doc/book/first-edition/src/concurrency.md @@ -237,7 +237,7 @@ This won't work, however, and will give us the error: ``` As the error message mentions, `Rc` cannot be sent between threads safely. This -is because the internal reference count is not maintained in a thread safe +is because the internal reference count is not maintained in a thread-safe manner and can have a data race. To solve this, we'll use `Arc`, Rust's standard atomic reference count type. @@ -288,7 +288,7 @@ involved—can cause data races! Usually when we wish to make something in an immutable position mutable, we use `Cell` or `RefCell` which allow safe mutation via runtime checks or otherwise (see also: [Choosing Your Guarantees](choosing-your-guarantees.html)). -However, similar to `Rc`, these are not thread safe. If we try using these, we +However, similar to `Rc`, these are not thread-safe. If we try using these, we will get an error about these types not being `Sync`, and the code will fail to compile. diff --git a/src/doc/book/first-edition/src/const-and-static.md b/src/doc/book/first-edition/src/const-and-static.md index 66a48566bd..e50a21367b 100644 --- a/src/doc/book/first-edition/src/const-and-static.md +++ b/src/doc/book/first-edition/src/const-and-static.md @@ -38,6 +38,9 @@ reference stored in a static has a [`'static` lifetime][lifetimes]: static NAME: &'static str = "Steve"; ``` +The type of a `static` value must be `Sync` unless the `static` value is +mutable. + [lifetimes]: lifetimes.html ## Mutability @@ -64,17 +67,20 @@ unsafe { [unsafe]: unsafe.html -Furthermore, any type stored in a `static` must be `Sync`, and must not have -a [`Drop`][drop] implementation. - -[drop]: drop.html - # Initializing Both `const` and `static` have requirements for giving them a value. They must be given a value that’s a constant expression. In other words, you cannot use the result of a function call or anything similarly complex or at runtime. +# Dropping + +Types implementing [`Drop`][drop] are allowed in `const` and `static` +definitions. Constants are inlined where they are used and are dropped +accordingly. `static` values are not dropped. + +[drop]: drop.html + # Which construct should I use? Almost always, if you can choose between the two, choose `const`. It’s pretty diff --git a/src/doc/book/first-edition/src/error-handling.md b/src/doc/book/first-edition/src/error-handling.md index 02bd67587a..e2f3995c5f 100644 --- a/src/doc/book/first-edition/src/error-handling.md +++ b/src/doc/book/first-edition/src/error-handling.md @@ -473,7 +473,7 @@ it also requires us to add a [`Debug`][8] constraint on the `E` type parameter (which represents our error type). Since the vast majority of types should satisfy the `Debug` constraint, this tends to work out in practice. (`Debug` on a type simply means that there's a reasonable -way to print a human readable description of values with that type.) +way to print a human-readable description of values with that type.) OK, let's move on to an example. @@ -554,7 +554,7 @@ fn main() { } ``` -This is a little better, but now we've written a lot more code! The case +This is a little better, but now we've written much more code! The case analysis has once again bitten us. Combinators to the rescue! Just like `Option`, `Result` has lots of combinators @@ -647,9 +647,9 @@ a bit nicer to deal with, since it will show your message instead of My advice boils down to this: use good judgment. There's a reason why the words “never do X†or “Y is considered harmful†don't appear in my writing. There are -trade offs to all things, and it is up to you as the programmer to determine +trade-offs to all things, and it is up to you as the programmer to determine what is acceptable for your use cases. My goal is only to help you evaluate -trade offs as accurately as possible. +trade-offs as accurately as possible. Now that we've covered the basics of error handling in Rust, and explained unwrapping, let's start exploring more of the standard @@ -815,7 +815,7 @@ type from `i32` to something else. The first thing we need to decide: should we use `Option` or `Result`? We certainly could use `Option` very easily. If any of the three errors occur, we could simply return `None`. This will work *and it is better than panicking*, -but we can do a lot better. Instead, we should pass some detail about the error +but we can do much better. Instead, we should pass some detail about the error that occurred. Since we want to express the *possibility of error*, we should use `Result`. But what should `E` be? Since two *different* types of errors can occur, we need to convert them to a common type. One such type is @@ -917,7 +917,7 @@ Reasonable people can disagree over whether this code is better than the code that uses combinators, but if you aren't familiar with the combinator approach, this code looks simpler to read to me. It uses explicit case analysis with `match` and `if let`. If an error occurs, it simply stops executing the -function and returns the error (by converting it to a string). +function and returns the error (by converting it to string). Isn't this a step backwards though? Previously, we said that the key to ergonomic error handling is reducing explicit case analysis, yet we've reverted @@ -1026,7 +1026,7 @@ use std::io; use std::num; // We derive `Debug` because all types should probably derive `Debug`. -// This gives us a reasonable human readable description of `CliError` values. +// This gives us a reasonable human-readable description of `CliError` values. #[derive(Debug)] enum CliError { Io(io::Error), @@ -1127,7 +1127,7 @@ use std::io; use std::num; // We derive `Debug` because all types should probably derive `Debug`. -// This gives us a reasonable human readable description of `CliError` values. +// This gives us a reasonable human-readable description of `CliError` values. #[derive(Debug)] enum CliError { Io(io::Error), @@ -1285,7 +1285,7 @@ macro_rules! try { ``` There's one tiny but powerful change: the error value is passed through -`From::from`. This makes the `try!` macro a lot more powerful because it gives +`From::from`. This makes the `try!` macro much more powerful because it gives you automatic type conversion for free. Armed with our more powerful `try!` macro, let's take a look at code we wrote @@ -1367,7 +1367,7 @@ use std::num; use std::path::Path; // We derive `Debug` because all types should probably derive `Debug`. -// This gives us a reasonable human readable description of `CliError` values. +// This gives us a reasonable human-readable description of `CliError` values. #[derive(Debug)] enum CliError { Io(io::Error), @@ -1643,7 +1643,7 @@ sure to add `extern crate csv;` to the top of your file.) use std::fs::File; // This struct represents the data in each row of the CSV file. -// Type based decoding absolves us of a lot of the nitty gritty error +// Type based decoding absolves us of a lot of the nitty-gritty error // handling, like parsing strings as integers or floats. #[derive(Debug, RustcDecodable)] struct Row { diff --git a/src/doc/book/first-edition/src/ffi.md b/src/doc/book/first-edition/src/ffi.md index b902fea448..0c01396c7c 100644 --- a/src/doc/book/first-edition/src/ffi.md +++ b/src/doc/book/first-edition/src/ffi.md @@ -532,10 +532,10 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `win64` * `sysv64` -Most of the abis in this list are self-explanatory, but the `system` abi may +Most of the ABIs in this list are self-explanatory, but the `system` ABI may seem a little odd. This constraint selects whatever the appropriate ABI is for interoperating with the target's libraries. For example, on win32 with a x86 -architecture, this means that the abi used would be `stdcall`. On x86_64, +architecture, this means that the ABI used would be `stdcall`. On x86_64, however, windows uses the `C` calling convention, so `C` would be used. This means that in our previous example, we could have used `extern "system" { ... }` to define a block for all windows systems, not only x86 ones. diff --git a/src/doc/book/first-edition/src/procedural-macros.md b/src/doc/book/first-edition/src/procedural-macros.md index 1c850b5c4a..a1cf2996b0 100644 --- a/src/doc/book/first-edition/src/procedural-macros.md +++ b/src/doc/book/first-edition/src/procedural-macros.md @@ -177,7 +177,7 @@ similar to regular macros work. You should check out the [docs](https://docs.rs/quote) for a good introduction. So I think that's it. Oh, well, we do need to add dependencies for `syn` and -`quote` in the `cargo.toml` for `hello-world-derive`. +`quote` in the `Cargo.toml` for `hello-world-derive`. ```toml [dependencies] diff --git a/src/doc/book/first-edition/src/release-channels.md b/src/doc/book/first-edition/src/release-channels.md index af89ca8348..f8c0e567a1 100644 --- a/src/doc/book/first-edition/src/release-channels.md +++ b/src/doc/book/first-edition/src/release-channels.md @@ -28,7 +28,7 @@ Generally speaking, unless you have a specific reason, you should be using the stable release channel. These releases are intended for a general audience. However, depending on your interest in Rust, you may choose to use nightly -instead. The basic tradeoff is this: in the nightly channel, you can use +instead. The basic trade-off is this: in the nightly channel, you can use unstable, new Rust features. However, unstable features are subject to change, and so any new nightly release may break your code. If you use the stable release, you cannot use experimental features, but the next release of Rust diff --git a/src/doc/book/redirects/associated-types.md b/src/doc/book/redirects/associated-types.md index 81aae63cd8..4083f93986 100644 --- a/src/doc/book/redirects/associated-types.md +++ b/src/doc/book/redirects/associated-types.md @@ -1,12 +1,23 @@ -% There is a new edition of the book +% Associated Types -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Associated types are a way of associating a type placeholder with a trait such that the trait method definitions can use these placeholder types in their signatures. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +pub trait Iterator { + type Item; + fn next(&mut self) -> Option; +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.03 — Advanced Traits][2]** +* [In the first edition: Ch 3.30 — Associated Types][1] [1]: first-edition/associated-types.html -[2]: second-edition/ch19-03-advanced-traits.html#associated-types +[2]: second-edition/ch19-03-advanced-traits.html#associated-types-specify-placeholder-types-in-trait-definitions diff --git a/src/doc/book/redirects/attributes.md b/src/doc/book/redirects/attributes.md index 2b32d89eff..2d7b05d065 100644 --- a/src/doc/book/redirects/attributes.md +++ b/src/doc/book/redirects/attributes.md @@ -1,12 +1,24 @@ -% There is a new edition of the book +% Attributes -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Any item declaration may have an attribute applied to it. -* [Index of the second edition of The Rust Programming Language][2] +```rust +// A function marked as a unit test +#[test] +fn test_foo() { + /* ... */ +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the Rust Reference: Ch 5.3 — Attributes][2]** +* [In the first edition: Ch 3.27 — Attributes][1] [1]: first-edition/attributes.html -[2]: second-edition/index.html +[2]: ../reference/attributes.html diff --git a/src/doc/book/redirects/bibliography.md b/src/doc/book/redirects/bibliography.md index 9f2e9dfa6d..740a26b3d3 100644 --- a/src/doc/book/redirects/bibliography.md +++ b/src/doc/book/redirects/bibliography.md @@ -1,12 +1,14 @@ -% There is a new edition of the book +% Bibliography -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +This page does not exist in [the second edition][2]. +You might be interested in a similar page in [the Rust Reference][3]. -* [Index of the second edition of The Rust Programming Language][2] +* **[In the Rust Reference: Appendix — Influences][3]** +* [In the first edition: Section 7 — Bibliography][1] [1]: first-edition/bibliography.html [2]: second-edition/index.html +[3]: ../reference/influences.html diff --git a/src/doc/book/redirects/borrow-and-asref.md b/src/doc/book/redirects/borrow-and-asref.md index 4525112ccc..2b8255bf19 100644 --- a/src/doc/book/redirects/borrow-and-asref.md +++ b/src/doc/book/redirects/borrow-and-asref.md @@ -1,12 +1,25 @@ -% There is a new edition of the book +% Borrow and AsRef -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> A cheap reference-to-reference conversion. +> Used to convert a value to a reference value within generic code. -* [Index of the second edition of The Rust Programming Language][2] +```rust +fn is_hello>(s: T) { + assert_eq!("hello", s.as_ref()); +} +``` + +--- + +This chapter does not exist in [the second edition][2]. +The best place to learn more about this is [the Rust documentation][3]. + +* **[In the Rust documentation: `convert::AsRef`][3]** +* [In the first edition: Ch 4.10 — Borrow and AsRef][1] [1]: first-edition/borrow-and-asref.html [2]: second-edition/index.html +[3]: ../std/convert/trait.AsRef.html diff --git a/src/doc/book/redirects/casting-between-types.md b/src/doc/book/redirects/casting-between-types.md index a4d901e264..9d773149aa 100644 --- a/src/doc/book/redirects/casting-between-types.md +++ b/src/doc/book/redirects/casting-between-types.md @@ -1,12 +1,32 @@ -% There is a new edition of the book +% Casting between types -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> A type cast expression is denoted with the binary operator `as`. +> Executing an `as` expression casts the value on the left-hand side to the type on the right-hand side. -* [Index of the second edition of The Rust Programming Language][2] +```rust +# fn sum(values: &[f64]) -> f64 { 0.0 } +# fn len(values: &[f64]) -> i32 { 0 } + +fn average(values: &[f64]) -> f64 { + let sum: f64 = sum(values); + let size: f64 = len(values) as f64; + sum / size +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Appendix A — Keywords][2]** +* [In the Rust Reference: Type Cast Expressions][3] +* [In the Rust documentation: `mem::transmute`][4] +* [In the first edition: Ch 3.29 — Casting between types][1] [1]: first-edition/casting-between-types.html -[2]: second-edition/index.html +[2]: second-edition/appendix-01-keywords.html +[3]: ../reference/expressions/operator-expr.html#type-cast-expressions +[4]: ../std/mem/fn.transmute.html \ No newline at end of file diff --git a/src/doc/book/redirects/choosing-your-guarantees.md b/src/doc/book/redirects/choosing-your-guarantees.md index 778891fdb6..e2205284b0 100644 --- a/src/doc/book/redirects/choosing-your-guarantees.md +++ b/src/doc/book/redirects/choosing-your-guarantees.md @@ -1,11 +1,21 @@ -% There is a new edition of the book +% Choosing your Guarantees -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Smart pointers are data structures that act like a pointer, but they also have additional metadata and capabilities. +> The different smart pointers defined in Rust’s standard library provide extra functionality beyond what references provide. -* [Related chapter in the second edition of The Rust Programming Language][2] +```rust +let b = Box::new(5); +println!("b = {}", b); +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 15.00 — Smart Pointers][2]** +* [In the first edition: Ch 4.8 — Choosing your Guarantees][1] [1]: first-edition/choosing-your-guarantees.html diff --git a/src/doc/book/redirects/closures.md b/src/doc/book/redirects/closures.md index 1f8f6aeee6..a3c6555e2f 100644 --- a/src/doc/book/redirects/closures.md +++ b/src/doc/book/redirects/closures.md @@ -1,11 +1,27 @@ -% There is a new edition of the book +% Closures -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Anonymous functions you can save in a variable or pass as arguments to other functions. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +# use std::thread; +# use std::time::Duration; + +let expensive_closure = |num| { + println!("calculating slowly..."); + thread::sleep(Duration::from_secs(2)); + num +}; +# expensive_closure(5); +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 13.01 — Closures][2]** +* [In the first edition: Ch 3.23 — Closures][1] [1]: first-edition/closures.html diff --git a/src/doc/book/redirects/comments.md b/src/doc/book/redirects/comments.md index bb921f4fe3..7766940fe7 100644 --- a/src/doc/book/redirects/comments.md +++ b/src/doc/book/redirects/comments.md @@ -1,11 +1,22 @@ -% There is a new edition of the book +% Comments -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Comments must start with two slashes and continue until the end of the line. +> For comments that extend beyond a single line, you’ll need to include // on each line. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +// So we’re doing something complicated here, long enough that we need +// multiple lines of comments to do it! Whew! Hopefully, this comment will +// explain what’s going on. +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 3.04 — Comments][2]** +* [In the first edition: Ch 3.4 — Comments][1] [1]: first-edition/comments.html diff --git a/src/doc/book/redirects/compiler-plugins.md b/src/doc/book/redirects/compiler-plugins.md index f92738f4ee..66061adf5a 100644 --- a/src/doc/book/redirects/compiler-plugins.md +++ b/src/doc/book/redirects/compiler-plugins.md @@ -1,6 +1,13 @@ -% The Rust Programming Language Has Moved +% Compiler Plugins -This chapter of the book has moved to [a chapter in the Unstable -Book][unstable book plugins]. Please check it out there. +There is a new edition of the book and this is an old link. -[unstable book plugins]: ../unstable-book/language-features/plugin.html +> Compiler plugins are user-provided libraries that extend the compiler's behavior with new syntax extensions, lint checks, etc. + +--- + +This particular chapter has moved to [the Unstable Book][2]. + +* **[In the Unstable Rust Book: `plugin`][2]** + +[2]: ../unstable-book/language-features/plugin.html diff --git a/src/doc/book/redirects/concurrency.md b/src/doc/book/redirects/concurrency.md index b9067cd90c..c2b96a55a3 100644 --- a/src/doc/book/redirects/concurrency.md +++ b/src/doc/book/redirects/concurrency.md @@ -1,11 +1,16 @@ -% There is a new edition of the book +% Concurrency -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Historically, programming [concurrency] has been difficult and error prone: Rust hopes to change that. +> Fearless concurrency allows you to write code that’s free of subtle bugs and is easy to refactor without introducing new bugs. -* [Related chapter in the second edition of The Rust Programming Language][2] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 16.00 — Fearless Concurrency][2]** +* [In the first edition: Ch 4.6 — Concurrency][1] [1]: first-edition/concurrency.html diff --git a/src/doc/book/redirects/conditional-compilation.md b/src/doc/book/redirects/conditional-compilation.md index b4fe83b96e..4e88da53b4 100644 --- a/src/doc/book/redirects/conditional-compilation.md +++ b/src/doc/book/redirects/conditional-compilation.md @@ -1,12 +1,28 @@ -% There is a new edition of the book +% Conditional Compilation -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Sometimes one wants to have different compiler outputs from the same code, depending on build target, such as targeted operating system, or to enable release builds. +> Configuration options are either provided by the compiler or passed in on the command line using. +> Rust code then checks for their presence using the `#[cfg(...)]` attribute -* [Index of the second edition of The Rust Programming Language][2] +```rust +// The function is only included in the build when compiling for macOS +#[cfg(target_os = "macos")] +fn macos_only() { + // ... +} +``` + +--- + +This particular chapter does not exist in [the second edition][2]. +The best place to learn about it is [the Rust Reference][3]. + +* **[In the Rust Reference: Ch 5.3 — Attributes, Conditional Compilation section][3]** +* [In the first edition: Ch 4.3 — Conditional Compilation][1] [1]: first-edition/conditional-compilation.html [2]: second-edition/index.html +[3]: ../reference/attributes.html#conditional-compilation diff --git a/src/doc/book/redirects/const-and-static.md b/src/doc/book/redirects/const-and-static.md index c8561df0da..2d7014a24f 100644 --- a/src/doc/book/redirects/const-and-static.md +++ b/src/doc/book/redirects/const-and-static.md @@ -1,12 +1,23 @@ -% There is a new edition of the book +% `const` and `static` -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Constants are _always_ immutable, and may only be set to a constant expression, not the result of a function call or any other value that could only be computed at runtime. +> +> Global variables are called `static` in Rust. -* [Related section about `const` in the second edition of The Rust Programming Language][2] -* [Related section about `static` in the second edition of The Rust Programming Language][3] +```rust +const MAX_POINTS: u32 = 100_000; +static HELLO_WORLD: &str = "Hello, world!"; +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 3.01 — Variables and Mutability, section Constants][2]** +* **[In the second edition: Ch 19.01 — Unsafe Rust, section Static Variables][3]** +* [In the first edition: Ch 3.26 — `const` and `static`][1] [1]: first-edition/const-and-static.html diff --git a/src/doc/book/redirects/crates-and-modules.md b/src/doc/book/redirects/crates-and-modules.md index 535d6ce48f..3796ed37d4 100644 --- a/src/doc/book/redirects/crates-and-modules.md +++ b/src/doc/book/redirects/crates-and-modules.md @@ -1,15 +1,28 @@ -% There is a new edition of the book +% Crates and Modules -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust has a module system that enables the reuse of code in an organized fashion. +> A module is a namespace that contains definitions of functions or types, and you can choose whether those definitions are visible outside their module (public) or not (private). +> +> A crate is a project that other people can pull into their projects as a dependency. -* [Related chapter about modules in the second edition of The Rust Programming Language][2] +```rust +mod network { + fn connect() { + } +} +``` -* [Related chapter about crates in the second edition of The Rust Programming Language][3] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 7.01 — `mod` and the Filesystem][2]** +* [In the second edition: Ch 14.02 — Publishing a Crate to Crates.io][2] +* [In the first edition: Ch 3.25 — Crates and Modules][1] [1]: first-edition/crates-and-modules.html -[2]: second-edition/ch07-00-modules.html -[3]: second-edition/ch14-00-more-about-cargo.html +[2]: second-edition/ch07-01-mod-and-the-filesystem.html +[3]: second-edition/ch14-02-publishing-to-crates-io.html diff --git a/src/doc/book/redirects/deref-coercions.md b/src/doc/book/redirects/deref-coercions.md index df927fcf80..29de95e66c 100644 --- a/src/doc/book/redirects/deref-coercions.md +++ b/src/doc/book/redirects/deref-coercions.md @@ -1,12 +1,30 @@ -% There is a new edition of the book +% Deref coercions -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Implementing the `Deref` trait allows us to customize the behavior of the _dereference operator_ `*`. +> By implementing `Deref` in such a way that a smart pointer can be treated like a regular reference, we can write code that operates on references and use that code with smart pointers too. -* [Related section in the second edition of The Rust Programming Language][2] +```rust +use std::ops::Deref; + +# struct MyBox(T); +impl Deref for MyBox { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 15.02 — Treating Smart Pointers like Regular References with the `Deref` Trait][2]** +* [In the first edition: Ch 3.33 — Deref coercions][1] [1]: first-edition/deref-coercions.html -[2]: second-edition/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods +[2]: second-edition/ch15-02-deref.html diff --git a/src/doc/book/redirects/documentation.md b/src/doc/book/redirects/documentation.md index 198da596f4..64382f33c5 100644 --- a/src/doc/book/redirects/documentation.md +++ b/src/doc/book/redirects/documentation.md @@ -1,11 +1,31 @@ -% There is a new edition of the book +% Documentation -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Documentation comments use `///` instead of `//` and support Markdown notation for formatting the text if you’d like. +> You place documentation comments just before the item they are documenting. -* [Related section in the second edition of The Rust Programming Language][2] +```rust,no_run +/// Adds one to the number given. +/// +/// # Examples +/// +/// ``` +/// let five = 5; +/// +/// assert_eq!(6, my_crate::add_one(5)); +/// ``` +pub fn add_one(x: i32) -> i32 { + x + 1 +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 14.02 — Publishing to crates.io, section Making useful documentation][2]** +* [In the first edition: Ch 4.4 — Documentation][1] [1]: first-edition/documentation.html diff --git a/src/doc/book/redirects/drop.md b/src/doc/book/redirects/drop.md index 9bb7ea991b..f5f01e377e 100644 --- a/src/doc/book/redirects/drop.md +++ b/src/doc/book/redirects/drop.md @@ -1,11 +1,33 @@ -% There is a new edition of the book +% Drop -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> `Drop` lets us customize what happens when a value is about to go out of scope. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +struct CustomSmartPointer { + data: String, +} + +impl Drop for CustomSmartPointer { + fn drop(&mut self) { + println!("Dropping CustomSmartPointer with data `{}`!", self.data); + } +} + +fn main() { + let c = CustomSmartPointer { data: String::from("my stuff") }; + let d = CustomSmartPointer { data: String::from("other stuff") }; + println!("CustomSmartPointers created."); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 15.03 — The `Drop` Trait Runs Code on Cleanup][2]** +* [In the first edition: Ch 3.20 — Drop][1] [1]: first-edition/drop.html diff --git a/src/doc/book/redirects/effective-rust.md b/src/doc/book/redirects/effective-rust.md index 286f9007e9..5c93d84b79 100644 --- a/src/doc/book/redirects/effective-rust.md +++ b/src/doc/book/redirects/effective-rust.md @@ -1,11 +1,13 @@ -% There is a new edition of the book +% Effective Rust -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +This section does not exist in [the second edition][2]. +However, the second edition encourages writing effective Rust from the start. +It is recommended to start there. -* [Index of the second edition of The Rust Programming Language][2] +* **[The second edition of The Rust Programming Language][2]** +* [In the first edition: Ch 4 — Effective Rust][1] [1]: first-edition/effective-rust.html diff --git a/src/doc/book/redirects/enums.md b/src/doc/book/redirects/enums.md index 5952358ee0..9b97970909 100644 --- a/src/doc/book/redirects/enums.md +++ b/src/doc/book/redirects/enums.md @@ -1,11 +1,22 @@ -% There is a new edition of the book +% Enums -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Enums allow you to define a type by enumerating its possible values. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +enum IpAddrKind { + V4, + V6, +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 6.01 — Defining an Enum][2]** +* [In the first edition: Ch 3.13 — Enums][1] [1]: first-edition/enums.html diff --git a/src/doc/book/redirects/error-handling.md b/src/doc/book/redirects/error-handling.md index 5243e11ecd..e915657ea4 100644 --- a/src/doc/book/redirects/error-handling.md +++ b/src/doc/book/redirects/error-handling.md @@ -1,11 +1,15 @@ -% There is a new edition of the book +% Error Handling -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust groups errors into two major categories: _recoverable_ errors with `Result` and _unrecoverable_ errors with `panic!`. -* [Related chapter in the second edition of The Rust Programming Language][2] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 9.00 — Error Handling][2]** +* [In the first edition: Ch 4.7 — Error Handling][1] [1]: first-edition/error-handling.html diff --git a/src/doc/book/redirects/ffi.md b/src/doc/book/redirects/ffi.md index 0c8116ee29..8a885928af 100644 --- a/src/doc/book/redirects/ffi.md +++ b/src/doc/book/redirects/ffi.md @@ -1,12 +1,29 @@ -% There is a new edition of the book +% FFI -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Sometimes, your Rust code may need to interact with code written in another language. +> To do this, Rust has a keyword, `extern`, that facilitates creating and using a _Foreign Function Interface_ (FFI). -* [Related section in the second edition of The Rust Programming Language][2] +```rust +extern "C" { + fn abs(input: i32) -> i32; +} + +fn main() { + unsafe { + println!("Absolute value of -3 according to C: {}", abs(-3)); + } +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.01 — Unsafe Rust, section `extern` functions][2]** +* [In the first edition: Ch 4.9 — FFI][1] [1]: first-edition/ffi.html -[2]: second-edition/ch19-01-unsafe-rust.html#calling-an-unsafe-function-or-method +[2]: second-edition/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code diff --git a/src/doc/book/redirects/functions.md b/src/doc/book/redirects/functions.md index 198a6dce14..5c61fe56b3 100644 --- a/src/doc/book/redirects/functions.md +++ b/src/doc/book/redirects/functions.md @@ -1,11 +1,29 @@ -% There is a new edition of the book +% Functions -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Function definitions in Rust start with `fn` and have a set of parentheses after the function name. +> The curly brackets tell the compiler where the function body begins and ends. +> We can call any function we’ve defined by entering its name followed by a set of parentheses. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +fn main() { + println!("Hello, world!"); + + another_function(); +} + +fn another_function() { + println!("Another function."); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the first edition: Ch 3.2 — Functions][1]** +* [In the second edition: Ch 3.03 — Functions][2] [1]: first-edition/functions.html diff --git a/src/doc/book/redirects/generics.md b/src/doc/book/redirects/generics.md index 333a979caf..8e52802dfa 100644 --- a/src/doc/book/redirects/generics.md +++ b/src/doc/book/redirects/generics.md @@ -1,11 +1,28 @@ -% There is a new edition of the book +% Generics -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Generics are abstract stand-ins for concrete types or other properties. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +struct Point { + x: T, + y: U, +} + +fn main() { + let both_integer = Point { x: 5, y: 10 }; + let both_float = Point { x: 1.0, y: 4.0 }; + let integer_and_float = Point { x: 5, y: 4.0 }; +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 10.00 — Generic Types, Traits, and Lifetimes][2]** +* [In the first edition: Ch 3.18 — Generics][1] [1]: first-edition/generics.html diff --git a/src/doc/book/redirects/getting-started.md b/src/doc/book/redirects/getting-started.md index 0b8296a0ab..168927c25a 100644 --- a/src/doc/book/redirects/getting-started.md +++ b/src/doc/book/redirects/getting-started.md @@ -1,11 +1,12 @@ -% There is a new edition of the book +% Getting Started -This is an old link. You can [continue to the exact older page][1]. +There is a new edition of the book and this is an old link. + +You can [continue to the exact older page][1]. If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. -* [This page in the first edition of the The Rust Programming Language][1] - -* [Related chapter in the second edition of The Rust Programming Language][2] +* **[In the second edition: Introduction][2]** +* [In the first edition: Getting Started][1] [1]: first-edition/getting-started.html diff --git a/src/doc/book/redirects/glossary.md b/src/doc/book/redirects/glossary.md index b044d2083f..6891dc1e05 100644 --- a/src/doc/book/redirects/glossary.md +++ b/src/doc/book/redirects/glossary.md @@ -1,11 +1,13 @@ -% There is a new edition of the book +% Glossary -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +This section does not exist in [the second edition][2]. +However, the second edition defines the terms it uses inline, rather than using a glossary. +It is recommended to start there. -* [Index of the second edition of The Rust Programming Language][2] +* **[The second edition of The Rust Programming Language][2]** +* [In the first edition: Glossary][1] [1]: first-edition/glossary.html diff --git a/src/doc/book/redirects/guessing-game.md b/src/doc/book/redirects/guessing-game.md index dd31e0829e..3a243dd4b8 100644 --- a/src/doc/book/redirects/guessing-game.md +++ b/src/doc/book/redirects/guessing-game.md @@ -1,11 +1,11 @@ -% There is a new edition of the book +% Tutorial: Guessing Game + +There is a new edition of the book and this is an old link. -This is an old link. You can [continue to the exact older page][1]. If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. -* [This page in the first edition of the The Rust Programming Language][1] - -* [Related chapter in second edition of The Rust Programming Language][2] +* **[In the first edition: Tutorial — Guessing Game][1]** +* [In the second edition: Ch 2.00 — Guessing Game tutorial][2] [1]: first-edition/guessing-game.html diff --git a/src/doc/book/redirects/if-let.md b/src/doc/book/redirects/if-let.md index 78de04ca7b..95da06a455 100644 --- a/src/doc/book/redirects/if-let.md +++ b/src/doc/book/redirects/if-let.md @@ -1,11 +1,22 @@ -% There is a new edition of the book +% if let -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> The `if let` syntax lets you combine `if` and `let` into a less verbose way to handle values that match one pattern and ignore the rest. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +let some_u8_value = Some(3u8); +if let Some(3) = some_u8_value { + println!("three"); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 6.03 — Concise Control Flow with `if let`][2]** +* [In the first edition: Ch 3.21 — if let][1] [1]: first-edition/if-let.html diff --git a/src/doc/book/redirects/if.md b/src/doc/book/redirects/if.md index dafc42f7c2..cf933a44d0 100644 --- a/src/doc/book/redirects/if.md +++ b/src/doc/book/redirects/if.md @@ -1,11 +1,27 @@ -% There is a new edition of the book +% if -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> An `if` expression allows us to branch our code depending on conditions. -* [Related section in second edition of The Rust Programming Language][2] +```rust +fn main() { + let number = 3; + + if number < 5 { + println!("condition was true"); + } else { + println!("condition was false"); + } +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 3.05 — Control flow][2]** +* [In the first edition: Ch 3.5 — if][1] [1]: first-edition/if.html diff --git a/src/doc/book/redirects/iterators.md b/src/doc/book/redirects/iterators.md index 8df24a17e2..03c7134126 100644 --- a/src/doc/book/redirects/iterators.md +++ b/src/doc/book/redirects/iterators.md @@ -1,11 +1,26 @@ -% There is a new edition of the book +% Iterators -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> The iterator pattern allows you to perform some task on a sequence of items in turn. +> An iterator is responsible for the logic of iterating over each item and determining when the sequence has finished. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +let v1 = vec![1, 2, 3]; + +let v1_iter = v1.iter(); + +for val in v1_iter { + println!("Got: {}", val); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 13.02 — Iterators][2]** +* [In the first edition: Ch 4.5 — Iterators][1] [1]: first-edition/iterators.html diff --git a/src/doc/book/redirects/lifetimes.md b/src/doc/book/redirects/lifetimes.md index 482ef64433..e9a5492719 100644 --- a/src/doc/book/redirects/lifetimes.md +++ b/src/doc/book/redirects/lifetimes.md @@ -1,13 +1,28 @@ -% There is a new edition of the book +% Lifetimes -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> 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. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +{ + let x = 5; // -----+-- 'b + // | + let r = &x; // --+--+-- 'a + // | | + println!("r: {}", r); // | | + // --+ | +} // -----+ +``` -* [Related page in the second edition of The Rust Programming Language (covering more advanced topics)][3] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 10.03 — Lifetimes][2]** +* [In the second edition: Ch 19.02 — Advanced Lifetimes][3] +* [In the first edition: Ch 3.10 — Lifetimes][1] [1]: first-edition/lifetimes.html diff --git a/src/doc/book/redirects/loops.md b/src/doc/book/redirects/loops.md index 4c7c6d9d5d..cabe918b4b 100644 --- a/src/doc/book/redirects/loops.md +++ b/src/doc/book/redirects/loops.md @@ -1,11 +1,35 @@ -% There is a new edition of the book +% Loops -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust has three kinds of loops: `loop`, `while`, and `for`. +> The `loop` keyword tells Rust to execute a block of code over and over again forever or until you explicitly tell it to stop. +> `while` loops evaluate a block of code until a condition ceases to be true. +> A `for` loop executes some code for each item in a collection. -* [Related section in the second edition of The Rust Programming Language][2] +```rust,no_run +loop { + println!("again!"); +} + +let mut number = 3; +while number != 0 { + println!("{}!", number); + number = number - 1; +} + +let a = [10, 20, 30, 40, 50]; +for element in a.iter() { + println!("the value is: {}", element); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 3.05 — Control flow][2]** +* [In the first edition: Ch 3.6 — Loops][1] [1]: first-edition/loops.html diff --git a/src/doc/book/redirects/macros.md b/src/doc/book/redirects/macros.md index 42a21c9457..d2c83ac500 100644 --- a/src/doc/book/redirects/macros.md +++ b/src/doc/book/redirects/macros.md @@ -1,12 +1,31 @@ -% There is a new edition of the book +% Macros -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> While functions and types abstract over code, macros abstract at a syntactic level. -* [Index of the second edition of The Rust Programming Language][2] +```rust +macro_rules! five_times { + ($x:expr) => (5 * $x); +} + +fn main() { + assert_eq!(25, five_times!(2 + 3)); +} +``` + +--- + +This chapter does not exist yet in [the second edition][2]. +You can check out other resources that describe macros. + +* **[Rust By Example: Macros][3]** +* [In the Rust Reference: Ch 3.1 — Macros by Example][4] +* [In the second edition: (future) Appendix D — Macros][2] +* [In the first edition: Ch 3.34 — Macros][1] [1]: first-edition/macros.html -[2]: second-edition/index.html +[2]: second-edition/appendix-04-macros.html +[3]: https://rustbyexample.com/macros.html +[4]: ../reference/macros-by-example.html \ No newline at end of file diff --git a/src/doc/book/redirects/match.md b/src/doc/book/redirects/match.md index 244617b5d6..5a32215ab4 100644 --- a/src/doc/book/redirects/match.md +++ b/src/doc/book/redirects/match.md @@ -1,13 +1,35 @@ -% There is a new edition of the book +% Match -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> `match` allows us to compare a value against a series of patterns and then execute code based on which pattern matches. +> Patterns can be made up of literal values, variable names, wildcards, and many other things. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +enum Coin { + Penny, + Nickel, + Dime, + Quarter, +} -* [Related chapter in the second edition of The Rust Programming Language (covering more advanced topics)][3] +fn value_in_cents(coin: Coin) -> u32 { + match coin { + Coin::Penny => 1, + Coin::Nickel => 5, + Coin::Dime => 10, + Coin::Quarter => 25, + } +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 6.02 — The `match` Control Flow Operator][2]** +* [In the second edition: Ch 18.00 — Patterns][3] +* [In the first edition: Ch 3.14 — Match][1] [1]: first-edition/match.html diff --git a/src/doc/book/redirects/method-syntax.md b/src/doc/book/redirects/method-syntax.md index c320c97201..a842c9badb 100644 --- a/src/doc/book/redirects/method-syntax.md +++ b/src/doc/book/redirects/method-syntax.md @@ -1,11 +1,28 @@ -% There is a new edition of the book +% Method Syntax -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Methods are different from functions in that they’re defined within the context of a struct, and their first parameter is always `self`, which represents the instance of the struct the method is being called on. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +# struct Rectangle { +# width: u32, +# height: u32, +# } + +impl Rectangle { + fn area(&self) -> u32 { + self.width * self.height + } +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 5.03 — Method Syntax][2]** +* [In the first edition: Ch 3.16 — Method Syntax][1] [1]: first-edition/method-syntax.html diff --git a/src/doc/book/redirects/mutability.md b/src/doc/book/redirects/mutability.md index 754a6b2310..6f48bc3065 100644 --- a/src/doc/book/redirects/mutability.md +++ b/src/doc/book/redirects/mutability.md @@ -1,11 +1,22 @@ -% There is a new edition of the book +% Mutability -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Variables are immutable only by default; we can make them mutable by adding mut in front of the variable name. -* [Related page in second edition of The Rust Programming Language][2] +```rust +let mut x = 5; +println!("The value of x is: {}", x); +x = 6; +println!("The value of x is: {}", x); +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 3.01 — Variables and Mutability][2]** +* [In the first edition: Ch 3.11 — Mutability][1] [1]: first-edition/mutability.html diff --git a/src/doc/book/redirects/operators-and-overloading.md b/src/doc/book/redirects/operators-and-overloading.md index 06a68dadfb..8094325e17 100644 --- a/src/doc/book/redirects/operators-and-overloading.md +++ b/src/doc/book/redirects/operators-and-overloading.md @@ -1,12 +1,43 @@ -% There is a new edition of the book +% Operators and Overloading -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust does not allow you to create your own operators or overload arbitrary operators, but the operations and corresponding traits listed in `std::ops` can be overloaded by implementing the traits associated with the operator. -* [Related section in the second edition of The Rust Programming Language][2] +```rust +use std::ops::Add; +#[derive(Debug,PartialEq)] +struct Point { + x: i32, + y: i32, +} + +impl Add for Point { + type Output = Point; + + fn add(self, other: Point) -> Point { + Point { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +fn main() { + assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, + Point { x: 3, y: 3 }); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.03 — Advanced Traits, section Operator Overloading][2]** +* [In the Rust documentation: `std::ops`][3] +* [In the first edition: Ch 3.32 — Operators and Overloading][1] [1]: first-edition/operators-and-overloading.html -[2]: second-edition/ch19-03-advanced-traits.html#operator-overloading-and-default-type-parameters +[2]: second-edition/ch19-03-advanced-traits.html#default-generic-type-parameters-and-operator-overloading +[3]: ../std/ops/index.html diff --git a/src/doc/book/redirects/ownership.md b/src/doc/book/redirects/ownership.md index 1b7e0eb992..adca776217 100644 --- a/src/doc/book/redirects/ownership.md +++ b/src/doc/book/redirects/ownership.md @@ -1,11 +1,19 @@ -% There is a new edition of the book +% Ownership -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Ownership is Rust’s most unique feature, and it enables Rust to make memory safety guarantees without needing a garbage collector. +> +> 1. Each value in Rust has a variable that’s called its _owner_. +> 2. There can only be one owner at a time. +> 3. When the owner goes out of scope, the value will be dropped. -* [Related chapter in the second edition of The Rust Programming Language][2] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 4.00 — Understanding Ownership][2]** +* [In the first edition: Ch 3.8 — Ownership][1] [1]: first-edition/ownership.html diff --git a/src/doc/book/redirects/patterns.md b/src/doc/book/redirects/patterns.md index 6bdbbfacfe..4044f16ab6 100644 --- a/src/doc/book/redirects/patterns.md +++ b/src/doc/book/redirects/patterns.md @@ -1,15 +1,31 @@ -% There is a new edition of the book +% Patterns -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Patterns are a special syntax within Rust for matching against the structure of our types, complex or simple. +> A pattern is made up of some combination of literals; destructured arrays, enums, structs, or tuples; variables, wildcards, and placeholders. +> These pieces describe the “shape†of the data we’re working with. -* [Related section in the second edition of The Rust Programming Language][2] +```rust +let x = Some(5); +let y = 10; -* [Related page in the second edition of The Rust Programming Language (covering more advanced topics)][3] +match x { + Some(50) => println!("Got 50"), + Some(y) => println!("Matched, y = {:?}", y), + _ => println!("Default case, x = {:?}", x), +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 18.03 — Patterns][2]** +* [In the second edition: Ch 6.02 — Match][3] +* [In the first edition: Ch 3.15 — Patterns][1] [1]: first-edition/patterns.html -[2]: second-edition/ch06-02-match.html#patterns-that-bind-to-values -[3]: second-edition/ch18-03-pattern-syntax.html +[2]: second-edition/ch18-00-patterns.html +[3]: second-edition/ch06-02-match.html#patterns-that-bind-to-values diff --git a/src/doc/book/redirects/primitive-types.md b/src/doc/book/redirects/primitive-types.md index 76f5f6c279..7244fbaa60 100644 --- a/src/doc/book/redirects/primitive-types.md +++ b/src/doc/book/redirects/primitive-types.md @@ -1,11 +1,23 @@ -% There is a new edition of the book +% Primitive Types -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust is a _statically typed_ language, which means that it must know the types of all variables at compile time. +> The compiler can usually infer what type we want to use based on the value and how we use it. +> In cases when many types are possible, a _type annotation_ must be added. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +let x = 2.0; // f64 + +let y: f32 = 3.0; // f32 +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 3.02 — Data Types][2]** +* [In the first edition: Ch 3.3 — Primitive Types][1] [1]: first-edition/primitive-types.html diff --git a/src/doc/book/redirects/procedural-macros.md b/src/doc/book/redirects/procedural-macros.md index 823efca6e8..4cf8ec6b65 100644 --- a/src/doc/book/redirects/procedural-macros.md +++ b/src/doc/book/redirects/procedural-macros.md @@ -1,13 +1,21 @@ -% There is a new edition of the book +% Procedural Macros (and custom Derive) -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Procedural macros allow for all sorts of advanced metaprogramming in Rust. -* [Index of the second edition of The Rust Programming Language][2] +--- +This chapter does not exist yet in [the second edition][2]. +You can check out other resources that describe macros. + +* **[In the Rust Reference: Ch 3.2 — Procedural Macros][4]** +* [The `proc_macro` crate documentation][3] +* [In the second edition: (future) Appendix D — Macros][2] +* [In the first edition: Ch 4.13 — Procedural Macros (and custom Derive)][1] [1]: first-edition/procedural-macros.html -[2]: second-edition/index.html +[2]: second-edition/appendix-04-macros.html +[3]: ../proc_macro/index.html +[4]: ../reference/procedural-macros.html \ No newline at end of file diff --git a/src/doc/book/redirects/raw-pointers.md b/src/doc/book/redirects/raw-pointers.md index c9259fd2ba..08a6900d79 100644 --- a/src/doc/book/redirects/raw-pointers.md +++ b/src/doc/book/redirects/raw-pointers.md @@ -1,11 +1,22 @@ -% There is a new edition of the book +% Raw Pointers -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Raw pointers are allowed to ignore many of the rules that references have to follow. -* [Related section in the second edition of The Rust Programming Language][2] +```rust +let mut num = 5; + +let r1 = &num as *const i32; +let r2 = &mut num as *mut i32; +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.01 — Unsafe Rust, section Dereferencing a Raw Pointer][2]** +* [In the first edition: Ch 3.35 — Raw Pointers][1] [1]: first-edition/raw-pointers.html diff --git a/src/doc/book/redirects/references-and-borrowing.md b/src/doc/book/redirects/references-and-borrowing.md index 2dc1f113c0..c3e29d671e 100644 --- a/src/doc/book/redirects/references-and-borrowing.md +++ b/src/doc/book/redirects/references-and-borrowing.md @@ -1,11 +1,23 @@ -% There is a new edition of the book +% References and Borrowing -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> A reference _refers_ to a value but does not own it. +> Because it does not own it, the value it points to will not be dropped when the reference goes out of scope. -* [Related page in second edition of The Rust Programming Language][2] +```rust +fn calculate_length(s: &String) -> usize { // s is a reference to a String + s.len() +} // Here, s goes out of scope. But because it does not have ownership of what + // it refers to, nothing happens. +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 4.02 — References and Borrowing][2]** +* [In the first edition: Ch 3.9 — References and Borrowing][1] [1]: first-edition/references-and-borrowing.html diff --git a/src/doc/book/redirects/release-channels.md b/src/doc/book/redirects/release-channels.md index ce4af005be..f54bbc21de 100644 --- a/src/doc/book/redirects/release-channels.md +++ b/src/doc/book/redirects/release-channels.md @@ -1,12 +1,28 @@ -% There is a new edition of the book +% Release Channels -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> The Rust project uses a concept called ‘release channels’ to manage releases. +> New nightly releases are created once a day. +> Every six weeks, the latest nightly release is promoted to ‘Beta’. +> At that point, it will only receive patches to fix serious errors. +> Six weeks later, the beta is promoted to ‘Stable’. -* [Index of the second edition of The Rust Programming Language][2] +--- + +This chapter does not exist yet in [the second edition][2]. +You can check out other resources that describe release channels. + +* **[In the Rustup documentation: Keeping Rust Up-to-date][4]** +* [On the website: Install Rust][5] +* [In the Rust RFCs: RFC 507 — Release Channels][3] +* [In the second edition: How Rust is Made and “Nightly Rustâ€][2] +* [In the first edition: Ch 4.11 — Release Channels][1] [1]: first-edition/release-channels.html -[2]: second-edition/index.html +[2]: second-edition/ch01-03-how-rust-is-made-and-nightly-rust.html +[3]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md +[4]: https://github.com/rust-lang-nursery/rustup.rs/blob/master/README.md#keeping-rust-up-to-date +[5]: https://www.rust-lang.org/en-US/install.html + diff --git a/src/doc/book/redirects/strings.md b/src/doc/book/redirects/strings.md index 8aaaab51eb..2e50d9d88c 100644 --- a/src/doc/book/redirects/strings.md +++ b/src/doc/book/redirects/strings.md @@ -1,16 +1,29 @@ -% There is a new edition of the book +% Strings -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> A `String` is allocated on the heap and as such is able to store an amount of text that is unknown to us at compile time. +> You can create a `String` from a string literal using the `from` function. +> A _string slice_ is a reference to part of a `String`. -* [Related section in second edition of The Rust Programming Language][2] +```rust +let s = String::from("hello world"); -* [Related page in second edition of The Rust Programming Language (covering more advanced topics)][3] +let hello = &s[0..5]; +let world = &s[6..11]; +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In second edition: Ch 8.02 — Strings][2]** +* [In second edition: Ch 4.01 — Ownership, section The String Type][3] +* [In second edition: Ch 4.03 — Slices, section String Slices][4] +* [In the first edition: Ch 3.17 — Strings][1] [1]: first-edition/strings.html -[2]: second-edition/ch04-03-slices.html#string-slices -[3]: second-edition/ch08-02-strings.html - +[2]: second-edition/ch08-02-strings.html +[3]: second-edition/ch04-01-what-is-ownership.html#the-string-type +[4]: second-edition/ch04-03-slices.html#string-slices diff --git a/src/doc/book/redirects/structs.md b/src/doc/book/redirects/structs.md index 4325281ce1..eb18820476 100644 --- a/src/doc/book/redirects/structs.md +++ b/src/doc/book/redirects/structs.md @@ -1,11 +1,24 @@ -% There is a new edition of the book +% Structs -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> A _struct_ is a custom data type that lets us name and package together multiple related values that make up a meaningful group. -* [Related chapter in second edition of The Rust Programming Language][2] +```rust +struct User { + username: String, + email: String, + sign_in_count: u64, + active: bool, +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In second edition: Ch 5.00 — Structs][2]** +* [In the first edition: Ch 3.12 — Structs][1] [1]: first-edition/structs.html diff --git a/src/doc/book/redirects/syntax-and-semantics.md b/src/doc/book/redirects/syntax-and-semantics.md index 666d1c1488..293f694fac 100644 --- a/src/doc/book/redirects/syntax-and-semantics.md +++ b/src/doc/book/redirects/syntax-and-semantics.md @@ -1,13 +1,14 @@ -% There is a new edition of the book +% Syntax and Semantics -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +Here are the relevant sections in the new and old books: -* [Related chapter in the second edition of The Rust Programming Language (covering Rust syntax in general)][2] -* [Related page in the second edition of The Rust Programming Language (covering Rust keywords)][3] -* [Related page in the second edition of The Rust Programming Language (covering Rust operators)][4] + +* **[In the second edition: Ch 3.00 — Common Programming Concepts][2]** +* [In the second edition: Appendix A — Keywords][3] +* [In the second edition: Appendix B — Operators][4] +* [In the first edition: Ch 3 — Syntax and Semantics][1] [1]: first-edition/syntax-and-semantics.html diff --git a/src/doc/book/redirects/syntax-index.md b/src/doc/book/redirects/syntax-index.md index 1a429505e2..cd03b67205 100644 --- a/src/doc/book/redirects/syntax-index.md +++ b/src/doc/book/redirects/syntax-index.md @@ -1,12 +1,14 @@ -% There is a new edition of the book +% Syntax Index -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +Here are the relevant sections in the new and old books: -* [Index of the second edition of The Rust Programming Language][2] +* **[In the second edition: Appendix A — Keywords][2]** +* **[In the second edition: Appendix B — Operators][3]** +* [In the first edition: Ch 6 — Syntax Index][1] [1]: first-edition/syntax-index.html -[2]: second-edition/index.html +[2]: second-edition/appendix-01-keywords.html +[3]: second-edition/appendix-02-operators.html diff --git a/src/doc/book/redirects/testing.md b/src/doc/book/redirects/testing.md index 0d6a0be75c..79b325b8ed 100644 --- a/src/doc/book/redirects/testing.md +++ b/src/doc/book/redirects/testing.md @@ -1,11 +1,24 @@ -% There is a new edition of the book +% Testing -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust includes support for writing software tests within the language itself. -* [Related chapter in the second edition of The Rust Programming Language][2] +```rust +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 11.00 — Testing][2]** +* [In the first edition: Ch 4.2 — Testing][1] [1]: first-edition/testing.html diff --git a/src/doc/book/redirects/the-stack-and-the-heap.md b/src/doc/book/redirects/the-stack-and-the-heap.md index 4986aa8a5a..59938b6bf9 100644 --- a/src/doc/book/redirects/the-stack-and-the-heap.md +++ b/src/doc/book/redirects/the-stack-and-the-heap.md @@ -1,11 +1,18 @@ -% There is a new edition of the book +% The Stack and the Heap -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Both the stack and the heap are parts of memory that is available to your code to use at runtime, but they are structured in different ways. +> The stack stores values in the order it gets them and removes the values in the opposite order. +> All data on the stack must take up a known, fixed size. +> For data with a size unknown to us at compile time or a size that might change, we can store data on the heap instead. -* [Related section in the second edition of The Rust Programming Language][2] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 4.01 — What is Ownership, section The Stack and the Heap][2]** +* [In the first edition: Ch 4.1 — The Stack and the Heap][1] [1]: first-edition/the-stack-and-the-heap.html diff --git a/src/doc/book/redirects/trait-objects.md b/src/doc/book/redirects/trait-objects.md index 64e05d6b48..869df02062 100644 --- a/src/doc/book/redirects/trait-objects.md +++ b/src/doc/book/redirects/trait-objects.md @@ -1,11 +1,67 @@ -% There is a new edition of the book +% Trait Objects -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Trait objects combine the data made up of the pointer to a concrete object with the behavior of the methods defined in the trait. +> A trait defines behavior that we need in a given situation. +> We can then use a trait as a trait object in places where we would use a concrete type or a generic type. -* [Related page in the second edition of The Rust Programming Language][2] +```rust,ignore +pub struct InputBox { + pub label: String, +} + +impl Draw for InputBox { + fn draw(&self) { + // Code to actually draw an input box + } +} + +pub struct Button { + pub label: String, +} + +impl Draw for Button { + fn draw(&self) { + // Code to actually draw a button + } +} + +pub struct Screen { + pub components: Vec, +} + +impl Screen + where T: Draw { + pub fn run(&self) { + for component in self.components.iter() { + component.draw(); + } + } +} + +fn main() { + let screen = Screen { + components: vec![ + Box::new(InputBox { + label: String::from("OK"), + }), + Box::new(Button { + label: String::from("OK"), + }), + ], + }; + + screen.run(); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 17.02 — Trait Objects][2]** +* [In the first edition: Ch 3.22 — Trait Objects][1] [1]: first-edition/trait-objects.html diff --git a/src/doc/book/redirects/traits.md b/src/doc/book/redirects/traits.md index 469f5c574a..baffad4a43 100644 --- a/src/doc/book/redirects/traits.md +++ b/src/doc/book/redirects/traits.md @@ -1,13 +1,22 @@ -% There is a new edition of the book +% Traits -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Traits abstract over behavior that types can have in common. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +pub trait Summarizable { + fn summary(&self) -> String; +} +``` -* [Related page in the second edition of The Rust Programming Language (covering more advanced topics)][3] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 10.02 — Traits][2]** +* [In the second edition: Ch 19.03 — Advanced Traits][3] +* [In the first edition: Ch 3.19 — Traits][1] [1]: first-edition/traits.html diff --git a/src/doc/book/redirects/type-aliases.md b/src/doc/book/redirects/type-aliases.md index 79eb5527bd..33e9f1faf7 100644 --- a/src/doc/book/redirects/type-aliases.md +++ b/src/doc/book/redirects/type-aliases.md @@ -1,11 +1,19 @@ -% There is a new edition of the book +% `type` aliases -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust provides the ability to declare a _type alias_ with the `type` keyword to give an existing type another name. -* [Related section in the second edition of The Rust Programming Language][2] +```rust +type Kilometers = i32; +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.04 — Advanced Types, section Type Synonyms][2]** +* [In the first edition: Ch 3.28 — `type` aliases][1] [1]: first-edition/type-aliases.html diff --git a/src/doc/book/redirects/ufcs.md b/src/doc/book/redirects/ufcs.md index 87438a1a38..eca6e6a9d9 100644 --- a/src/doc/book/redirects/ufcs.md +++ b/src/doc/book/redirects/ufcs.md @@ -1,12 +1,54 @@ -% There is a new edition of the book +% Universal Function Call Syntax -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust cannot prevent a trait from having a method with the same name as another trait’s method, nor can it prevent us from implementing both of these traits on one type. +> In order to be able to call each of the methods with the same name, then, we need to tell Rust which one we want to use. -* [Related section in the second edition of The Rust Programming Language][2] +```rust +trait Pilot { + fn fly(&self); +} + +trait Wizard { + fn fly(&self); +} + +struct Human; + +impl Pilot for Human { +# fn fly(&self) { +# println!("This is your captain speaking."); +# } +} + +impl Wizard for Human { +# fn fly(&self) { +# println!("Up!"); +# } +} + +impl Human { +# fn fly(&self) { +# println!("*waving arms furiously*"); +# } +} + +fn main() { + let person = Human; + Pilot::fly(&person); + Wizard::fly(&person); + person.fly(); +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.03 — Advanced Traits, section Fully Qualified Syntax][2]** +* [In the first edition: Ch 3.24 — Universal Function Call Syntax][1] [1]: first-edition/ufcs.html -[2]: second-edition/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation +[2]: second-edition/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name diff --git a/src/doc/book/redirects/unsafe.md b/src/doc/book/redirects/unsafe.md index e8e5a03479..73685fc83d 100644 --- a/src/doc/book/redirects/unsafe.md +++ b/src/doc/book/redirects/unsafe.md @@ -1,12 +1,18 @@ -% There is a new edition of the book +% `unsafe` -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust has a second language hiding out inside of it, unsafe Rust, which does not enforce memory safety guarantees. -* [Related page in the second edition of The Rust Programming Language][2] +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.01 — Unsafe Rust][2]** +* [The Rustonomicon, The Dark Arts of Advanced and Unsafe Rust Programming][3] +* [In the first edition: Ch 3.36 — `unsafe`][1] [1]: first-edition/unsafe.html [2]: second-edition/ch19-01-unsafe-rust.html +[3]: ../nomicon/index.html diff --git a/src/doc/book/redirects/unsized-types.md b/src/doc/book/redirects/unsized-types.md index 05ac4100ad..d209c0d3bc 100644 --- a/src/doc/book/redirects/unsized-types.md +++ b/src/doc/book/redirects/unsized-types.md @@ -1,11 +1,23 @@ -% There is a new edition of the book +% Unsized Types -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Sometimes referred to as ‘DSTs’ or ‘unsized types’, these types let us talk about types whose size we can only know at runtime. +> The `Sized` trait is automatically implemented for everything the compiler knows the size of at compile time. +> A trait bound on `?Sized` is the opposite of a trait bound on `Sized`; that is, we would read this as “`T` may or may not be `Sized`â€. -* [Related section in the second edition of The Rust Programming Language][2] +```rust,ignore +fn generic(t: &T) { + // ...snip... +} +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 19.04 — Advanced Types, section Dynamically Sized Types][2]** +* [In the first edition: Ch 3.31 — Unsized Types][1] [1]: first-edition/unsized-types.html diff --git a/src/doc/book/redirects/using-rust-without-the-standard-library.md b/src/doc/book/redirects/using-rust-without-the-standard-library.md index fd5c29967f..06deb6ee46 100644 --- a/src/doc/book/redirects/using-rust-without-the-standard-library.md +++ b/src/doc/book/redirects/using-rust-without-the-standard-library.md @@ -1,12 +1,17 @@ -% There is a new edition of the book +% Using Rust without the Standard Library -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Rust’s standard library provides a lot of useful functionality, but assumes support for various features of its host system: threads, networking, heap allocation, and others. +> There are systems that do not have these features, however. -* [Index of the second edition of The Rust Programming Language][2] +--- + +This particular chapter has moved to [the Unstable Book][2]. + +* **[In the Unstable Rust Book: `lang_items` — Writing an executable without stdlib][2]** +* [In the first edition: Ch 4.12 — Using Rust without the Standard Library][1] [1]: first-edition/using-rust-without-the-standard-library.html -[2]: second-edition/index.html +[2]: ../unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib diff --git a/src/doc/book/redirects/variable-bindings.md b/src/doc/book/redirects/variable-bindings.md index 7476d63505..fcafa7e2af 100644 --- a/src/doc/book/redirects/variable-bindings.md +++ b/src/doc/book/redirects/variable-bindings.md @@ -1,12 +1,20 @@ -% There is a new edition of the book +% Variable Bindings -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Variable bindings bind some value to a name, so it can be used later. -* [Index of the second edition of The Rust Programming Language][2] +```rust +let foo = 5; +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 2.00 — Guessing Game Tutorial, section Variables][2]** +* [In the first edition: Ch 3.1 — Variable Bindings][1] [1]: first-edition/variable-bindings.html -[2]: second-edition/index.html +[2]: second-edition/ch02-00-guessing-game-tutorial.html#storing-values-with-variables diff --git a/src/doc/book/redirects/vectors.md b/src/doc/book/redirects/vectors.md index bf2ad1c01a..ac05844842 100644 --- a/src/doc/book/redirects/vectors.md +++ b/src/doc/book/redirects/vectors.md @@ -1,11 +1,21 @@ -% There is a new edition of the book +% Vectors -This is an old link. You can [continue to the exact older page][1]. -If you're trying to learn Rust, checking out [the second edition][2] might be a better choice. +There is a new edition of the book and this is an old link. -* [This page in the first edition of the The Rust Programming Language][1] +> Vectors store more than one value in a single data structure that puts all the values next to each other in memory. +> Vectors can only store values of the same type. -* [Related page in the second edition of The Rust Programming Language][2] +```rust +let v: Vec = Vec::new(); +let numbers = vec![1, 2, 3]; +``` + +--- + +Here are the relevant sections in the new and old books: + +* **[In the second edition: Ch 8.01 — Vectors][2]** +* [In the first edition: Ch 3.7 — Vectors][1] [1]: first-edition/vectors.html diff --git a/src/doc/book/second-edition/book.toml b/src/doc/book/second-edition/book.toml index fef7c06146..9789a435c2 100644 --- a/src/doc/book/second-edition/book.toml +++ b/src/doc/book/second-edition/book.toml @@ -1,2 +1,3 @@ +[book] title = "The Rust Programming Language" author = "Steve Klabnik and Carol Nichols, with Contributions from the Rust Community" diff --git a/src/doc/book/second-edition/dictionary.txt b/src/doc/book/second-edition/dictionary.txt index f95332b009..3f2c8f43aa 100644 --- a/src/doc/book/second-edition/dictionary.txt +++ b/src/doc/book/second-edition/dictionary.txt @@ -23,12 +23,14 @@ async atomics AveragedCollection backend +backported backtrace backtraces BACKTRACE Backtraces Baz’s benchmarking +bioinformatics bitand BitAnd BitAndAssign @@ -57,6 +59,7 @@ cargodoc ChangeColor ChangeColorMessage charset +choo chXX chYY coercions @@ -71,6 +74,7 @@ couldn CPUs cratesio CRLF +cryptocurrencies cryptographically CStr CString @@ -79,6 +83,7 @@ Ctrl customizable CustomSmartPointer CustomSmartPointers +data’s deallocate deallocated deallocating @@ -102,6 +107,7 @@ destructures destructuring Destructuring deterministically +DevOps didn Dobrý doccargo @@ -144,6 +150,7 @@ FnBox FnMut FnOnce formatter +formatters FrenchToast FromIterator frontend @@ -175,6 +182,9 @@ html hyperoptimize Iceburgh ident +IDE +IDEs +IDE's IEEE impl implementor @@ -223,6 +233,7 @@ lookup loopback lossy lval +macOS mathematic memoization metadata @@ -243,6 +254,7 @@ monomorphized MoveMessage Mozilla mpsc +msvc MulAssign multibyte multithreaded @@ -266,7 +278,6 @@ newtypes nitty nocapture nomicon -Nomicon nonequality NotFound null's @@ -344,6 +355,8 @@ Rustaceans rUsT rustc rustdoc +Rustonomicon +rustfmt rustup screenshot searchstring @@ -359,6 +372,7 @@ Simula situps sizeof Smalltalk +snuck someproject someusername SPDX @@ -393,6 +407,7 @@ submodules Submodules suboptimal substring +subteams subtree subtyping Summarizable @@ -406,7 +421,6 @@ TextField That'd there'd ThreadPool -threadsafe timestamp Tiếng timeline @@ -415,10 +429,13 @@ TODO TokenStream toml TOML +toolchain +toolchains ToString tradeoff tradeoffs TrafficLight +transcoding trpl tuesday tuple @@ -454,6 +471,7 @@ variant's vers versa Versioning +visualstudio vtable wasn WeatherForecast diff --git a/src/doc/book/second-edition/dot/trpl04-01.dot b/src/doc/book/second-edition/dot/trpl04-01.dot index 24f6964208..331d591338 100644 --- a/src/doc/book/second-edition/dot/trpl04-01.dot +++ b/src/doc/book/second-edition/dot/trpl04-01.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl04-02.dot b/src/doc/book/second-edition/dot/trpl04-02.dot index d785760812..e46d2ed4aa 100644 --- a/src/doc/book/second-edition/dot/trpl04-02.dot +++ b/src/doc/book/second-edition/dot/trpl04-02.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl04-03.dot b/src/doc/book/second-edition/dot/trpl04-03.dot index 2ddc335abb..16c0b28607 100644 --- a/src/doc/book/second-edition/dot/trpl04-03.dot +++ b/src/doc/book/second-edition/dot/trpl04-03.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl04-04.dot b/src/doc/book/second-edition/dot/trpl04-04.dot index 87b1303e13..1c95c231c3 100644 --- a/src/doc/book/second-edition/dot/trpl04-04.dot +++ b/src/doc/book/second-edition/dot/trpl04-04.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl04-05.dot b/src/doc/book/second-edition/dot/trpl04-05.dot index 55aa221fd6..ca1f7e06e9 100644 --- a/src/doc/book/second-edition/dot/trpl04-05.dot +++ b/src/doc/book/second-edition/dot/trpl04-05.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl04-06.dot b/src/doc/book/second-edition/dot/trpl04-06.dot index a81d208fb8..a23f179a77 100644 --- a/src/doc/book/second-edition/dot/trpl04-06.dot +++ b/src/doc/book/second-edition/dot/trpl04-06.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl15-01.dot b/src/doc/book/second-edition/dot/trpl15-01.dot index 217d6d09e4..e8b95f9a3f 100644 --- a/src/doc/book/second-edition/dot/trpl15-01.dot +++ b/src/doc/book/second-edition/dot/trpl15-01.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl15-02.dot b/src/doc/book/second-edition/dot/trpl15-02.dot index bdd8b517a1..f7dfd22c97 100644 --- a/src/doc/book/second-edition/dot/trpl15-02.dot +++ b/src/doc/book/second-edition/dot/trpl15-02.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/dot/trpl15-03.dot b/src/doc/book/second-edition/dot/trpl15-03.dot index 5626de2485..16f026814b 100644 --- a/src/doc/book/second-edition/dot/trpl15-03.dot +++ b/src/doc/book/second-edition/dot/trpl15-03.dot @@ -1,5 +1,6 @@ digraph { rankdir=LR; + overlap=false; dpi=300.0; node [shape="plaintext"]; diff --git a/src/doc/book/second-edition/nostarch/chapter01.md b/src/doc/book/second-edition/nostarch/chapter01.md index 6d2e2123a3..07cb241287 100644 --- a/src/doc/book/second-edition/nostarch/chapter01.md +++ b/src/doc/book/second-edition/nostarch/chapter01.md @@ -1,99 +1,261 @@ + +[TOC] + # Introduction -Welcome to “The Rust Programming Languageâ€, an introductory book about Rust. -Rust is a programming language that’s focused on safety, speed, and -concurrency. Its design lets you create programs that have the performance and -control of a low-level language, but with helpful abstractions that feel like a -high-level language. The Rust community welcomes all programmers who have their -experience in languages like C and are looking for a safer alternative, as well -as programmers from languages like Python who are looking for ways to write more -performant code without losing expressiveness. +Welcome to “The Rust Programming Language,†an introductory book about Rust. -Rust provides the majority of its safety checks at compile time and without a -garbage collector so that your program’s runtime isn’t impacted. This makes it -useful in a number of use cases that other languages aren’t good at: embedding -in other languages, programs with specific space and time requirements, and -writing low-level code, like device drivers and operating systems. It’s also -great for web applications: it powers the Rust package registry site, crates.io! -We’re excited to see what _you_ create with Rust. +Rust is a programming language that helps you write faster, more reliable +software. High-level ergonomics and low-level control are often at odds with +each other in programming language design; Rust stands to challenge that. +Through balancing powerful technical capacity and a great developer experience, +Rust gives you the option to control low-level details (such as memory usage) +without all the hassle traditionally associated with such control. -This book is written for a reader who already knows how to program in at least -one programming language. After reading this book, you should be comfortable -writing Rust programs. We’ll be learning Rust through small, focused examples -that build on each other to demonstrate how to use various features of Rust as -well as how they work behind the scenes. +## Who Rust is For -## Contributing to the book +Rust is great for many people for a variety of reasons. Let’s discuss a few of +the most important groups. -This book is open source. If you find an error, please don’t hesitate to file an -issue or send a pull request on GitHub at *https://github.com/rust-lang/book*. +### Teams of Developers + +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 +developers. In Rust, the compiler plays a gatekeeper role by refusing to +compile code with these kinds of bugs--including concurrency bugs. By working +alongside the compiler, the team can spend more time focusing on the logic of +the program rather than chasing down bugs. + +Rust also brings contemporary developer tools to the systems programming world: + +* Cargo, the included dependency manager and build tool, makes adding, + compiling, and managing dependencies painless and consistent across the Rust + ecosystem. +* Rustfmt ensures a consistent coding style across developers. +* The Rust Language Server powers IDE integration for code completion and + inline error messages. + +By using these and other tools in the Rust ecosystem, developers can be +productive while writing systems-level code. + +### Students + +Rust is for students and people who are interested in learning about systems +concepts. Many people have learned about topics like operating systems +development through Rust. The community is happy to answer student questions. +Through efforts such as this book, the Rust teams want to make systems concepts +more accessible to more people, especially those getting started with +programming. + +### Companies + +Rust is used in production by hundreds of companies, large and small, for a +variety of tasks, such as command line tools, web services, DevOps tooling, +embedded devices, audio and video analysis and transcoding, cryptocurrencies, +bioinformatics, search engines, internet of things applications, machine +learning, and even major parts of the Firefox web browser. + +### Open Source Developers + +Rust is for people who want to build the Rust programming language, community, +developer tools, and libraries. We’d love for you to contribute to the Rust +language. + +### People Who Value Speed and Stability + +By speed, we mean both the speed of the programs that Rust lets you create 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. + +This isn’t a complete list of everyone the Rust language hopes to support, but +these are some of the biggest stakeholders. Overall, Rust’s greatest ambition +is to take trade-offs that have been accepted by programmers for decades and +eliminate the dichotomy. Safety *and* productivity. Speed *and* ergonomics. +Give Rust a try, and see if its choices work for you. + +## Who This Book is For + +This book assumes that you’ve written code in some other programming language, +but doesn’t make any assumptions about which one. We’ve tried to make the +material broadly accessible to those from a wide variety of programming +backgrounds. We don’t spend a lot of time talking about what programming *is* +or how to think about it; someone new to programming entirely would be better +served by reading a book specifically providing an introduction to programming. + +## How to Use This Book + +This book generally assumes that you’re reading it front-to-back, that is, +later chapters build on top of concepts in earlier chapters, and earlier +chapters may not dig into details on a topic, revisiting the topic in a later +chapter. + +There are two kinds of chapters in this book: concept chapters, and project +chapters. In concept chapters, you’ll learn about an aspect of Rust. In the +project chapters, we’ll build small programs together, applying what we’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 Rust as a language. We’ll +cover concepts at a high level, and later chapters will go into them in detail. +If you’re the kind of person who likes to get their hands dirty right away, +Chapter 2 is great for that. If you’re *really* that kind of person, you may +even wish to skip over Chapter 3, which covers features that are very similar +to other programming languages, and go straight to Chapter 4 to learn about +Rust’s ownership system. By contrast, if you’re a particularly meticulous +learner who prefers to learn every detail before moving onto the next, you may +want to skip Chapter 2 and go straight to Chapter 3. + +In the end, there’s no wrong way to read a book: if you want to skip ahead, go +for it! You may have to jump back if you find things confusing. Do whatever +works for you. + +An important part of the process of learning Rust is learning how to read the +error messages that the compiler gives you. As such, we’ll be showing a lot of +code that doesn’t compile, and the error message the compiler will show you in +that situation. As such, if you pick a random example, it may not compile! +Please read the surrounding text to make sure that you didn’t happen to pick +one of the in-progress examples. + +Finally, there are some appendices. These contain useful information about the +language in a more reference-like format. + +## Contributing to the Book + +This book is open source. If you find an error, please don’t hesitate to file +an issue or send a pull request on GitHub at +*https://github.com/rust-lang/book*. Please see CONTRIBUTING.md at +*https://github.com/rust-lang/book/blob/master/CONTRIBUTING.md* for more +details. ## Installation The first step to using Rust is to install it. You’ll need an internet connection to run the commands in this chapter, as we’ll be downloading Rust -from the internet. +from the internet. We’ll actually be installing Rust using `rustup`, a +command-line tool for managing Rust versions and associated tools. -We’ll be showing off a number of commands using a terminal, and those lines all -start with `$`. You don’t need to type in the `$`s; they are there to indicate -the start of each command. You’ll see many tutorials and examples around the web -that follow 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. +The following steps will install the latest stable version of the Rust +compiler. The examples and output shown in this book used stable Rust 1.21.0. +Due to Rust’s stability guarantees, which we’ll discuss further in the “How +Rust is Made†section later in this chapter, all of the examples that compile +will continue to compile with newer versions of Rust. The output may differ +slightly as error messages and warnings are often improved. In other words, the +newer, stable version of Rust you will install with these steps should work as +expected with the content of this book. -### Installing on Linux or Mac +> #### Command Line Notation +> +> We’ll be showing off a number of commands using a terminal, and those lines +> all start with `$`. You don’t need to type in the `$` character; they are +> there to indicate the start of each command. You’ll see many tutorials and +> examples around the web that follow 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 `$`. -If you’re on Linux or a Mac, all you need to do is open a terminal and type -this: +### Installing Rustup on Linux or Mac -```bash +If you’re on Linux or a Mac, 99% of what you need to do is open a terminal and +type this: + +``` $ curl https://sh.rustup.rs -sSf | sh ``` -This will download a script and start the installation. You may be prompted for -your password. If it all goes well, you’ll see this appear: +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: -```bash +``` Rust is installed now. Great! ``` -### Installing on Windows +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’re on Windows, please go to *https://rustup.rs/* and follow -the instructions to download rustup-init.exe. Run that and follow the rest of -the instructions. +The installation script automatically adds Rust to your system PATH after your +next login. If you want to start using Rust right away, run the following +command in your shell: -The rest of the Windows-specific commands in the book will assume that you are -using `cmd` as your shell. If you use a different shell, you may be able to run -the same commands that Linux and Mac users do. If neither work, consult the -documentation for the shell you are using. +``` +$ source $HOME/.cargo/env +``` + +Alternatively, add the following line to your `~/.bash_profile`: + +``` +$ export PATH="$HOME/.cargo/bin:$PATH" +``` + +Finally, you’ll need a linker of some kind. You likely have one installed. If +not, when you compile a Rust program, you’ll get errors that a linker could not +be executed. Check your platform’s documentation for how to install a C +compiler; they usually come with the correct linker as well, given that C needs +one. You may want to install a C compiler regardless of your need for only a +linker; some common Rust packages depend on C code and will need a C compiler +too. + +### Installing Rustup on Windows + +On Windows, go to https://www.rust-lang.org/en-US/install.html at +*https://www.rust-lang.org/en-US/install.html* and follow the instructions. +You’ll also need the C++ build tools for Visual Studio 2013 or later. The +easiest way to acquire the build tools is by installing Build Tools for Visual +Studio 2017 at *https://www.visualstudio.com/downloads/* which provides only +the Visual C++ build tools. Alternately, you can install at +*https://www.visualstudio.com/downloads/* Visual Studio 2017, Visual Studio +2015, or Visual Studio 2013 and during installation select the desktop +development with C++ workload. + +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 at *https://www.rust-lang.org/install.html* for other options. + +### Updating + +Once you have Rust installed via `rustup`, updating to the latest version is +easy. From your shell, run the update script: + +``` +$ rustup update +``` ### Uninstalling -Uninstalling Rust is as easy as installing it. From your shell, run -the uninstall script: +Uninstalling Rust and Rustup is as easy as installing them. From your shell, +run the uninstall script: -```bash +``` $ rustup self uninstall ``` ### Troubleshooting -If you’ve got Rust installed, you can open up a shell, and type this: +To check that you have Rust installed, you can open up a shell and type this: -```bash +``` $ rustc --version ``` You should see the version number, commit hash, and commit date in a format similar to this for the latest stable version at the time you install: -```bash +``` rustc x.y.z (abcabcabc yyyy-mm-dd) ``` -If you see this, Rust has been installed successfully! -Congrats! +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. @@ -103,16 +265,20 @@ The easiest is the #rust IRC channel on irc.mozilla.org, which you can access through Mibbit at *http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust*. 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 user’s forum +ourselves) who can help you out. Other great resources include the Users forum at *https://users.rust-lang.org/* and Stack Overflow at *http://stackoverflow.com/questions/tagged/rust*. -### Local documentation +### Local Documentation 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! + ## Hello, World! Now that you have Rust installed, let’s write your first Rust program. It’s @@ -122,106 +288,152 @@ tradition. > 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 to the command line, feel free to use your -> favorite IDE. +> 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 +> has been made rapidly on that front! -### Creating a Project File +### Creating a Project Directory -First, make a file to put your Rust code in. Rust doesn’t care where your code -lives, but for this book, we’d 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 directory for this particular project: +First, make a directory to put your Rust code in. Rust doesn’t care where your +code lives, but for this book, we’d 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 +inside that for the “Hello, world!†project: Linux and Mac: -```bash +``` $ mkdir ~/projects $ cd ~/projects $ mkdir hello_world $ cd hello_world ``` -Windows: +Windows CMD: -```bash -$ mkdir %USERPROFILE%\projects -$ cd %USERPROFILE%\projects -$ mkdir hello_world -$ cd hello_world +``` +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\projects" +> mkdir hello_world +> cd hello_world +``` + +Windows PowerShell: + +``` +> mkdir $env:USERPROFILE\projects +> cd $env:USERPROFILE\projects +> mkdir hello_world +> cd hello_world ``` ### Writing and Running a Rust Program -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`. +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*. -Now open the `main.rs` file you just created, and type the following code: +Now open the *main.rs* file you just created, and enter the code shown in +Listing 1-1: Filename: main.rs -```rust +``` fn main() { println!("Hello, world!"); } ``` -Save the file, and go back to your terminal window. On Linux or OSX, enter the -following commands: +Listing 1-1: A program that prints “Hello, world!†-```bash +Save the file, and go back to your terminal window. On Linux or macOS, enter +the following commands: + +``` $ rustc main.rs $ ./main Hello, world! ``` -On Windows, just replace `./main` with `.\main.exe`. Regardless of your -operating system, you should see the string `Hello, world!` print to the -terminal. If you did, then congratulations! You’ve officially written a Rust -program. That makes you a Rust programmer! Welcome. +On Windows, use `.\main.exe` instead of `./main`. + +``` +> rustc main.rs +> .\main.exe +Hello, world! +``` + +Regardless of your operating system, you should see the string `Hello, world!` +print to the terminal. If you did, then 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: -```rust +``` fn main() { } ``` These lines define a *function* in Rust. The `main` function is special: it’s -the first thing that is run for every executable Rust program. The first line -says, “I’m declaring a function named `main` that takes no arguments and -returns nothing.†If there were arguments, they would go inside the parentheses, -`(` and `)`. +the first code that is run for 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 `)`. -Also note that the function body is wrapped in curly braces, `{` and `}`. Rust -requires these around all function bodies. It’s considered good style to put -the opening curly brace on the same line as the function declaration, with one -space in between. +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 +put the opening curly bracket on the same line as the function declaration, +with one space in between. -Inside the `main()` function: +> 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. -```rust +Inside the `main` function, we have this code: + +``` 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 that are important here. The first is -that it’s indented with four spaces, not a tab. +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. -The second important part is `println!()`. This is calling a Rust *macro*, -which is how metaprogramming is done in Rust. If it were calling a function -instead, it would look like this: `println()` (without the `!`). We’ll discuss -Rust macros in more detail in Chapter XX, but for now you just need to know -that when you see a `!` that means that you’re calling a macro instead of a -normal function. +The second important part is `println!`. This is calling a Rust *macro*, which +is how metaprogramming is done in Rust. If it were calling a function instead, +it would look like this: `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 means that you’re calling a macro instead of a normal function. + +> ### Why `println!` is a Macro +> +> There are multiple reasons why `println!` is a macro rather than a function, +> and we haven’t really explained Rust yet, so it’s not exactly obvious. Here +> are the reasons: +> +> * The string passed to `println!` can have formatting specifiers in it, +> and those are checked at compile-time. +> * Rust functions can only have a fixed number of arguments, but `println!` +> (and macros generally) can take a variable number. +> * The formatting specifiers can have named arguments, which Rust functions +> cannot. +> * It implicitly takes its arguments by reference even when they’re passed +> by value. +> +> If none of this makes sense, don’t worry about it. We’ll cover these concepts +> in more detail later. Next is `"Hello, world!"` which is a *string*. We pass this string as an -argument to `println!()`, which prints the string to the screen. Easy enough! +argument to `println!`, which prints the string to the screen. Easy enough! The line ends with a semicolon (`;`). The `;` indicates that this expression is over, and the next one is ready to begin. Most lines of Rust code end with a @@ -229,58 +441,62 @@ over, and the next one is ready to begin. Most lines of Rust code end with a ### Compiling and Running Are Separate Steps -In “Writing and Running a Rust Programâ€, we showed you how to run a newly -created program. We’ll break that process down and examine each step now. +In the “Writing and Running a Rust Program†section on page XX, we showed you +how to run a newly created program. We’ll break that process down and examine +each step now. Before running a Rust program, you have to compile it. You can use the Rust compiler by entering the `rustc` command and passing it the name of your source file, like this: -```bash +``` $ 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 should output a binary -executable, which you can see on Linux or OSX by entering the `ls` command in -your shell as follows: +`gcc` or `clang`. After compiling successfully, Rust outputs a binary +executable. -```bash +On Linux, Mac, and PowerShell on Windows, you can see the executable by +entering the `ls` command in your shell as follows: + +``` $ ls main main.rs ``` -On Windows, you’d enter: +With CMD on Windows, you’d enter: -```bash -$ dir /B # the /B option says to only show the file names +``` +> dir /B %= the /B option says to only show the file names =% main.exe +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 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: -```bash +``` $ ./main # or .\main.exe on Windows ``` -If `main.rs` were your “Hello, world!†program, this would print `Hello, +If *main.rs* were your “Hello, world!†program, this 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 it 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 +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. 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 your project has -and make it easy to share your code with other people and projects. Next, we’ll +grows, you’ll want to be able to manage all of the options your project has and +make it easy to share your code with other people and projects. Next, we’ll introduce you to a tool called Cargo, which will help you write real-world Rust programs. @@ -300,11 +516,11 @@ easier to do. As the vast, vast majority of Rust projects use Cargo, we will assume that you’re using it for the rest of the book. Cargo comes installed with Rust -itself, if you used the official installers as covered in the Installation -chapter. If you installed Rust through some other means, you can check if you +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 typing the following into your terminal: -```bash +``` $ cargo --version ``` @@ -318,44 +534,45 @@ Let’s create a new project using Cargo and look at how it differs from our project in `hello_world`. Go back to your projects directory (or wherever you decided to put your code): -Linux and Mac: +Linux, Mac, and PowerShell: -```bash +``` $ cd ~/projects ``` -Windows: +CMD for Windows: -```bash -$ cd %USERPROFILE%\projects +``` +> cd \d "%USERPROFILE%\projects" ``` And then on any operating system run: -```bash +``` $ cargo new hello_cargo --bin $ cd hello_cargo ``` We passed the `--bin` argument to `cargo new` because our goal is to make an -executable application, as opposed to a library. Executables are often called -*binaries* (as in `/usr/bin`, if you’re on a Unix system). We’ve given -`hello_cargo` as the name for our project, and Cargo creates its files in a -directory of the same name that we can then go into. +executable application, as opposed to a library. Executables are binary +executable files often called just *binaries*. We’ve given `hello_cargo` as the +name for our project, and Cargo creates its files in a directory of the same +name that we can then go into. -If we list the files in the `hello_cargo` directory, we can 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 in the `hello_cargo` directory for us, along with a `.gitignore` -file; you can change this to use a different version control system, or no -version control system, by using the `--vcs` flag. +If we list the files in the *hello_cargo* directory, we can 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 in the *hello_cargo* directory for us, along with a *.gitignore* +file. 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. -Open up `Cargo.toml` in your text editor of choice. It should look something -like this: +Open up *Cargo.toml* in your text editor of choice. It should look similar to +the code in Listing 1-2: Filename: Cargo.toml -```toml +``` [package] name = "hello_cargo" version = "0.1.0" @@ -364,9 +581,10 @@ authors = ["Your Name "] [dependencies] ``` +Listing 1-2: Contents of *Cargo.toml* generated by `cargo new` + This file is in the *TOML* (Tom’s Obvious, Minimal Language) format. TOML is -similar to INI but has some extra goodies and is used as Cargo’s -configuration format. +used as Cargo’s configuration format. The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to @@ -382,50 +600,52 @@ The last line, `[dependencies]`, is the start of a section for you to list any *crates* (which is what we call packages of Rust code) that your project will depend on so that Cargo knows to download and compile those too. We won’t need any other crates for this project, but we will in the guessing game tutorial in -the next chapter. +Chapter 2. -Now let’s look at `src/main.rs`: +Now let’s look at *src/main.rs*: Filename: src/main.rs -```rust +``` fn main() { println!("Hello, world!"); } ``` -Cargo has generated a “Hello World!†for you, just like the one we wrote -earlier! So that part is the same. The differences between our previous project -and the project generated by Cargo that we’ve seen so far are: +Cargo has generated a “Hello World!†for you, just like the one we wrote in +Listing 1-1! So that part is the same. The differences between our previous +project and the project generated by Cargo that we’ve seen so far are: -1. Our code goes in the `src` directory -2. The top level contains a `Cargo.toml` configuration file +- Our code goes in the *src* directory +- The top level contains a *Cargo.toml* configuration file -Cargo expects your source files to live inside the `src` directory so that the +Cargo expects your source files to live inside the *src* directory so that 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. 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 your code into the `src` directory and creating an appropriate -`Cargo.toml`. +the *hello_world* directory, you can convert it to a project that does use +Cargo by moving your code into the *src* directory and creating an appropriate +*Cargo.toml*. ### Building and Running a Cargo Project Now let’s look at what’s different about building and running your Hello World program through Cargo! To do so, enter the following commands: -```bash +``` $ cargo build Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) + Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs ``` -This should have created an executable file in `target/debug/hello_cargo` (or -`target\debug\hello_cargo.exe` on Windows), which you can run with this command: +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: -```bash +``` $ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows Hello, world! ``` @@ -433,27 +653,18 @@ 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 looks like this: - -Filename: Cargo.lock - -```toml -[root] -name = "hello_cargo" -version = "0.1.0" -``` - -Cargo uses the `Cargo.lock` file to keep track of dependencies in your -application. This project doesn’t have dependencies, so the file is a bit -sparse. Realistically, you won’t ever need to touch this file yourself; just -let Cargo handle it. +at the top level called *Cargo.lock*. Cargo uses *Cargo.lock* to keep track of +the exact versions of dependencies used to build 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. We just built a project with `cargo build` and ran it with -`./target/debug/hello_cargo`, but we can actually do both in one step with -`cargo run` as follows: +`./target/debug/hello_cargo`, but we can also use `cargo run` to compile and +then run: -```bash +``` $ cargo run + Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/hello_cargo` Hello, world! ``` @@ -461,22 +672,39 @@ 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 something like +rebuilt the project before running it, and you would have seen output like this: -```bash +``` $ cargo run Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) + Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs Running `target/debug/hello_cargo` Hello, world! ``` +Finally, there’s `cargo check`. This will quickly check your code to make sure +that it compiles, but not bother producing an executable: + +``` +$ cargo check + Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) + 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 Cargo can skip the entire step of producing the +executable. If we’re checking our work throughout the process of writing the +code, this will speed things up! As such, many Rustaceans run `cargo check` 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. + So a few more differences we’ve now seen: -3. Instead of using `rustc`, build a project using `cargo build` (or build and - run it in one step with `cargo run`) -4. 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. +- Instead of using `rustc`, build a project using `cargo build` or + `cargo check` (or build and run it 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. The other 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 @@ -486,14 +714,14 @@ providing specific instructions for Linux and Mac versus Windows. 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 +executable in *target/release* instead of *target/debug*. These optimizations make your Rust code run faster, but turning them on makes your program take longer to compile. 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 -building the final program you’ll give to a user that won’t be rebuilt and -that we want to 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`. +building the final program you’ll give to a user that won’t be rebuilt and that +we want to 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*. ### Cargo as Convention @@ -501,16 +729,245 @@ 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 Cargo, you can just run `cargo build`, and it should work the -right way. Even though this project is simple, it now uses much of the real -tooling you’ll use for the rest of your Rust career. In fact, you can get -started with virtually all Rust projects you want to work -on with the following commands: +right way. -```bash +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, you can get +started with virtually all Rust projects you want to work on with the following +commands to check out the code using Git, change into the project directory, +and build: + +``` $ git clone someurl.com/someproject $ cd someproject $ cargo build ``` -> Note: If you want to look at Cargo in more detail, check out the official -Cargo guide at *http://doc.crates.io/guide.html*, which covers all of its features. +If you want to look at Cargo in more detail, check out its documentation at +*https://doc.rust-lang.org/cargo/*, which covers all of its features. + +## How Rust is Made and “Nightly Rust†+ +Before we dive into the language itself, we’d like to finish up the +introductory chapter by talking about how Rust is made, and how that affects +you as a Rust developer. We mentioned in the “Installation†section 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! + +### Stability Without Stagnation + +As a language, Rust cares a *lot* about the stability of your code. We want +Rust to be a rock-solid foundation you can build on, and if things were +constantly changing, that would be impossible. At the same time, if we can’t +experiment with new features, we may not find out important flaws until after +their release, when we can no longer change things. + +Our solution to this problem is what we call “stability without stagnation†and +is the way we can change and improve Rust while making sure that using Rust +stays nice, stable, and boring. + +Our guiding principle for Rust releases is this: you should never have to fear +upgrading to a new version of stable Rust. Each upgrade should be painless. At +the same time, the upgrade should bring you new features, fewer bugs, and +faster compile times. + +### Choo, Choo! Release Channels and Riding the Trains + +Rust development operates on a *train schedule*. That is, all development is +done on the `master` branch of the Rust repository. Releases follow a software +release train model, which has been used by Cisco IOS and other software +projects. There are three *release channels* for Rust: + +* Nightly +* Beta +* Stable + +Most Rust developers primarily use the stable channel, but those who want to +try out experimental new features may use nightly or beta. + +Here’s an example of how the development and release process works: let’s +assume that the Rust team is working on the release of Rust 1.5. That release +happened in December of 2015, but it will provide us with realistic version +numbers. A new feature is added to Rust: a new commit lands on the `master` +branch. Each night, a new nightly version of Rust is produced. Every day is a +release day, and these releases are created by our release infrastructure +automatically. So as time passes, our releases look like this, once a night: + +``` +nightly: * - - * - - * +``` + +Every six weeks, it’s time to prepare a new release! The `beta` branch of the +Rust repository branches off from the `master` branch used by nightly. Now, +there are two releases: + +``` +nightly: * - - * - - * + | +beta: * +``` + +Most Rust users do not use beta releases actively, but test against beta in +their CI system to help Rust discover possible regressions. In the meantime, +there’s still a nightly release every night: + +``` +nightly: * - - * - - * - - * - - * + | +beta: * +``` + +Let’s say a regression is found. Good thing we had some time to test the beta +release before the regression snuck into a stable release! The fix is applied +to `master`, so that nightly is fixed, and then the fix is backported to the +`beta` branch, and a new release of beta is produced: + +``` +nightly: * - - * - - * - - * - - * - - * + | +beta: * - - - - - - - - * +``` + +Six weeks after the first beta was created, it’s time for a stable release! The +`stable` branch is produced from the `beta` branch: + +``` +nightly: * - - * - - * - - * - - * - - * - * - * + | +beta: * - - - - - - - - * + | +stable: * +``` + +Hooray! Rust 1.5 is done! However, we’ve forgotten one thing: because the six +weeks have gone by, we also need a new beta of the *next* version of Rust, 1.6. +So after `stable` branches off of `beta`, the next version of `beta` branches +off of `nightly` again: + +``` +nightly: * - - * - - * - - * - - * - - * - * - * + | | +beta: * - - - - - - - - * * + | +stable: * +``` + +This is called the “train model†because every six weeks, a release “leaves the +stationâ€, but still has to take a journey through the beta channel before it +arrives as a stable release. + +Rust releases every six weeks, like clockwork. If you know the date of one Rust +release, you can know the date of the next one: it’s six weeks later. A nice +aspect of having releases scheduled every six weeks is that the next train is +coming soon. If a feature happens to miss a particular release, there’s no need +to worry: another one is happening in a short time! This helps reduce pressure +to sneak possibly unpolished features in close to the release deadline. + +Thanks to this process, you can always check out the next build of Rust and +verify for yourself that it’s easy to upgrade to: if a beta release doesn’t +work as expected, you can report it to the team and get it fixed before the +next stable release happens! Breakage in a beta release is relatively rare, but +`rustc` is still a piece of software, and bugs do exist. + +### Unstable Features + +There’s one more catch with this release model: unstable features. Rust uses a +technique called “feature flags†to determine what features are enabled in a +given release. If a new feature is under active development, it lands on +`master`, and therefore, in nightly, but behind a *feature flag*. If you, as a +user, wish to try out the work-in-progress feature, you can, but you must be +using a nightly release of Rust and annotate your source code with the +appropriate flag to opt in. + +If you’re using a beta or stable release of Rust, you can’t use any feature +flags. This is the key that allows us to get practical use with new features +before we declare them stable forever. Those who wish to opt into the bleeding +edge can do so, and those who want a rock-solid experience can stick with +stable and know that their code won’t break. Stability without stagnation. + +This book only contains information about stable features, as in-progress +features are still changing, and surely they’ll be different between when this +book was written and when they get enabled in stable builds. You can find +documentation for nightly-only features online. + +### Rustup and the Role of Rust Nightly + +Rustup makes it easy to change between different release channels of Rust, on a +global or per-project basis. By default, you’ll have stable Rust installed. To +install nightly, for example: + +``` +$ 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: + +``` +> rustup toolchain list +stable-x86_64-pc-windows-msvc (default) +beta-x86_64-pc-windows-msvc +nightly-x86_64-pc-windows-msvc +``` + +As you can see, the stable toolchain is the default. Most Rust users use stable +most of the time. You might want to use stable most of the time, but use +nightly on a specific project, because you care about a cutting-edge feature. +To do so, you can use `rustup override` in that project’s directory to set the +nightly toolchain as the one `rustup` should use when you’re in that directory: + +``` +$ cd ~/projects/needs-nightly +$ rustup override add nightly +``` + +Now, every time you call `rustc` or `cargo` inside of +*~/projects/needs-nightly*, `rustup` will make sure that you are using nightly +Rust, rather than your default of stable Rust. This comes in handy when you +have a lot of Rust projects! + +### The RFC Process and Teams + +So how do you learn about these new features? Rust’s development model follows +a *Request For Comments (RFC) process*. If you’d like an improvement in Rust, +you can write up a proposal, called an RFC. + +Anyone can write RFCs to improve Rust, and the proposals are reviewed and +discussed by the Rust team, which is comprised of many topic subteams. There’s +a full list of the teams on Rust’s +website at *https://www.rust-lang.org/en-US/team.html*, which includes teams for +each area of the project: language design, compiler implementation, +infrastructure, documentation, and more. The appropriate team reads the +proposal and the comments, writes some comments of their own, and eventually, +there’s consensus to accept or reject the feature. + +If the feature is accepted, an issue is opened on the Rust repository, and +someone can implement it. The person who implements it very well may not be the +person who proposed the feature in the first place! When the implementation is +ready, it lands on the `master` branch behind a feature gate, as we discussed +in the “Unstable Features†section. + +After some time, once Rust developers who use nightly releases have been able +to try out the new feature, team members will discuss the feature, how it’s +worked out on nightly, and decide if it should make it into stable Rust or not. +If the decision is to move forward, the feature gate is removed, and the +feature is now considered stable! It rides the trains into a new stable release +of Rust. + +## Summary + +You’re already off to a great start on your Rust journey! In this chapter, +you’ve: + +* Learned what makes Rust unique +* Installed the latest stable version of Rust +* Written a “Hello, world!†program using both `rustc` directly and using + the conventions of `cargo` +* Found out about how Rust is developed + +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. diff --git a/src/doc/book/second-edition/nostarch/chapter09.md b/src/doc/book/second-edition/nostarch/chapter09.md index 0e9b90d000..297e80eb8d 100644 --- a/src/doc/book/second-edition/nostarch/chapter09.md +++ b/src/doc/book/second-edition/nostarch/chapter09.md @@ -19,7 +19,7 @@ location beyond the end of an array. Most languages don’t distinguish between these two kinds of errors and handle both in the same way using mechanisms like exceptions. Rust doesn’t have -exceptions. Instead, it has the value `Result` for recoverable errors and +exceptions. Instead, it has the type `Result` for recoverable errors and the `panic!` macro that stops execution when it encounters unrecoverable errors. This chapter covers calling `panic!` first and then talks about returning `Result` values. Additionally, we’ll explore considerations to @@ -70,15 +70,14 @@ $ cargo run Compiling panic v0.1.0 (file:///projects/panic) Finished dev [unoptimized + debuginfo] target(s) in 0.25 secs Running `target/debug/panic` -thread 'main' panicked at 'crash and burn', src/main.rs:2 +thread 'main' panicked at 'crash and burn', src/main.rs:2:4 note: Run with `RUST_BACKTRACE=1` for a backtrace. -error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) ``` 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* indicates that it’s the second line -of our *src/main.rs* file. +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 @@ -132,17 +131,16 @@ $ cargo run Compiling panic v0.1.0 (file:///projects/panic) Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs Running `target/debug/panic` - thread 'main' panicked at 'index out of bounds: the len is 3 but the index is -100', /stable-dist-rustc/build/src/libcollections/vec.rs:1362 +99', /checkout/src/liballoc/vec.rs:1555:10 note: Run with `RUST_BACKTRACE=1` for a backtrace. error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) ``` -This error points at a file we didn’t write, *libcollections/vec.rs*. That’s -the implementation of `Vec` in the standard library. The code that gets run -when we use `[]` on our vector `v` is in *libcollections/vec.rs*, and that is -where the `panic!` is actually happening. +This error points at a file we didn’t write, *vec.rs*. That’s the +implementation of `Vec` in the standard library. The code that gets run when +we use `[]` on our vector `v` is in *vec.rs*, and that is where the `panic!` is +actually happening. The next note line tells us that we can set the `RUST_BACKTRACE` environment variable to get a backtrace of exactly what happened to cause the error. A @@ -160,7 +158,7 @@ $ RUST_BACKTRACE=1 cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/panic` thread 'main' panicked at 'index out of bounds: the len is 3 but the index is -100', /checkout/src/liballoc/vec.rs:1555:10 +99', /checkout/src/liballoc/vec.rs:1555:10 stack backtrace: 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49 @@ -186,7 +184,7 @@ stack backtrace: 10: as core::ops::index::Index>::index at /checkout/src/liballoc/vec.rs:1555 11: panic::main - at ./src/main.rs:4 + at src/main.rs:4 12: __rust_maybe_catch_panic at /checkout/src/libpanic_unwind/lib.rs:99 13: std::rt::lang_start @@ -213,7 +211,7 @@ want our program to panic, the location pointed to by the first line mentioning a file we wrote is where we should start investigating to figure out how we got to this location with values that caused the panic. In Listing 9-1 where we deliberately wrote code that would panic in order to demonstrate how to use -backtraces, the way to fix the panic is to not request an element at index 100 +backtraces, the way to fix the panic is to not request an element at index 99 from a vector that only contains three items. When your code panics in the future, you’ll need to figure out what action the code is taking with what values that causes the panic and what the code should do instead. @@ -230,9 +228,9 @@ interpret and respond to. For example, if we try to open a file and that operation fails because the file doesn’t exist, we might want to create the file instead of terminating the process. -Recall in Chapter 2 in the “Handling Potential Failure with the `Result` Type†-section that the `Result` enum is defined as having two variants, `Ok` and -`Err`, as follows: +Recall from “Handling Potential Failure with the `Result` Type†in Chapter 2 +that the `Result` enum is defined as having two variants, `Ok` and `Err`, as +follows: ``` enum Result { @@ -288,7 +286,7 @@ error[E0308]: mismatched types `std::result::Result` | = note: expected type `u32` - = note: found type `std::result::Result` + found type `std::result::Result` ``` This tells us the return type of the `File::open` function is a `Result`. @@ -350,7 +348,7 @@ code, we’ll see the following output from the `panic!` macro: ``` thread 'main' panicked at 'There was a problem opening the file: Error { repr: -Os { code: 2, message: "No such file or directory" } }', src/main.rs:8 +Os { code: 2, message: "No such file or directory" } }', src/main.rs:9:12 ``` As usual, this output tells us exactly what has gone wrong. @@ -367,6 +365,9 @@ Listing 9-4. Look at Listing 9-5, which adds another arm to the `match`: Filename: src/main.rs + + ``` use std::fs::File; use std::io::ErrorKind; @@ -451,7 +452,7 @@ the `panic!` call that the `unwrap` method makes: ``` thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "No such file or directory" } }', -/stable-dist-rustc/build/src/libcore/result.rs:868 +src/libcore/result.rs:906:4 ``` Another method, `expect`, which is similar to `unwrap`, lets us also choose the @@ -476,8 +477,7 @@ will be the parameter that we pass to `expect`, rather than the default ``` thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code: -2, message: "No such file or directory" } }', -/stable-dist-rustc/build/src/libcore/result.rs:868 +2, message: "No such file or directory" } }', src/libcore/result.rs:906:4 ``` Because this error message starts with the text we specified, `Failed to open @@ -600,18 +600,16 @@ 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. -The one difference between the `match` expression from Listing 9-6 and what the -question mark operator does is that when using the question mark operator, -error values go through the `from` function defined in the `From` trait in the -standard library. Many error types implement the `from` function to convert an -error of one type into an error of another type. When used by the question mark -operator, the call to the `from` function converts the error type that the -question mark operator gets into the error type defined in the return type of -the current function that we’re using `?` in. This is useful when parts of a -function might fail for many different reasons, but the function returns one -error type that represents all the ways the function might fail. As long as -each error type implements the `from` function to define how to convert itself -to the returned error type, the question mark operator takes care of the +There is a difference between what the `match` expression from Listing 9-6 and +the question mark 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 question mark 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 question mark operator takes care of the conversion automatically. In the context of Listing 9-7, the `?` at the end of the `File::open` call will @@ -673,14 +671,14 @@ fn main() { When we compile this code, we get the following error message: ``` -error[E0277]: the `?` operator can only be used in a function that returns -`Result` (or another type that implements `std::ops::Try`) +error[E0277]: the trait bound `(): std::ops::Try` is not satisfied --> src/main.rs:4:13 | 4 | let f = File::open("hello.txt")?; | ------------------------ | | - | cannot use the `?` operator in a function that returns `()` + | the `?` operator can only be used in a function that returns + `Result` (or another type that implements `std::ops::Try`) | in this macro invocation | = help: the trait `std::ops::Try` is not implemented for `()` @@ -749,7 +747,7 @@ example: ``` use std::net::IpAddr; -let home = "127.0.0.1".parse::().unwrap(); +let home: IpAddr = "127.0.0.1".parse().unwrap(); ``` We’re creating an `IpAddr` instance by parsing a hardcoded string. We can see @@ -837,7 +835,7 @@ number being in range, like so: ``` loop { - // snip + // --snip-- let guess: i32 = match guess.trim().parse() { Ok(num) => num, @@ -850,7 +848,7 @@ loop { } match guess.cmp(&secret_number) { - // snip + // --snip-- } ``` diff --git a/src/doc/book/second-edition/nostarch/chapter11.md b/src/doc/book/second-edition/nostarch/chapter11.md index 799ec38056..fa385ad129 100644 --- a/src/doc/book/second-edition/nostarch/chapter11.md +++ b/src/doc/book/second-edition/nostarch/chapter11.md @@ -3,7 +3,7 @@ # Writing Automated Tests -In his 1972 essay “The Humble Programmer,†Edsger W. Dijkstra said that +In his 1972 essay, “The Humble Programmer,†Edsger W. Dijkstra said that “Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.†That doesn’t mean we shouldn’t try to test as much as we can! Correctness in our programs is the @@ -250,13 +250,13 @@ let’s look at some macros other than `panic!` that are useful in tests. The `assert!` macro, provided by the standard library, is useful when you want to ensure that some condition in a test evaluates to `true`. We give the -`assert!` macro an argument that evaluates to a boolean. If the value is +`assert!` macro an argument that evaluates to a Boolean. If the value is `true`, `assert!` does nothing and the test passes. If the value is `false`, the `assert!` macro calls the `panic!` macro, which causes the test to fail. Using the `assert!` macro helps us check that our code is functioning in the way we intend. -In Chapter 5, Listing 5-9, we used a `Rectangle` struct and a `can_hold` +In Chapter 5, Listing 5-15, we used a `Rectangle` struct and a `can_hold` method, which are repeated here in Listing 11-5. Let’s put this code in the *src/lib.rs* file and write some tests for it using the `assert!` macro. @@ -279,7 +279,7 @@ impl Rectangle { Listing 11-5: Using the `Rectangle` struct and its `can_hold` method from Chapter 5 -The `can_hold` method returns a boolean, which means it’s a perfect use case +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 @@ -472,6 +472,7 @@ failures: thread 'tests::it_adds_two' panicked at 'assertion failed: `(left == right)` left: `4`, right: `5`', src/lib.rs:11:8 +note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: tests::it_adds_two @@ -574,8 +575,8 @@ test tests::greeting_contains_name ... FAILED failures: ---- tests::greeting_contains_name stdout ---- - thread 'tests::greeting_contains_name' panicked at 'assertion failed: - result.contains("Carol")', src/lib.rs:12:8 + thread 'tests::greeting_contains_name' panicked at 'assertion failed: +result.contains("Carol")', src/lib.rs:12:8 note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: @@ -603,8 +604,8 @@ Now when we run the test, we’ll get a more informative error message: ``` ---- tests::greeting_contains_name stdout ---- - thread 'tests::greeting_contains_name' panicked at 'Greeting did not contain - name, value was `Hello!`', src/lib.rs:12:8 + thread 'tests::greeting_contains_name' panicked at 'Greeting did not +contain name, value was `Hello!`', src/lib.rs:12:8 note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` diff --git a/src/doc/book/second-edition/nostarch/chapter12.md b/src/doc/book/second-edition/nostarch/chapter12.md index f1ce8c85de..a1dc2a44f8 100644 --- a/src/doc/book/second-edition/nostarch/chapter12.md +++ b/src/doc/book/second-edition/nostarch/chapter12.md @@ -62,9 +62,10 @@ $ cargo run searchstring example-filename.txt ``` Right now, the program generated by `cargo new` cannot process arguments we -give it. However, some existing libraries on *https://crates.io/* can help -us with writing a program that accepts command line arguments, but because -you’re just learning this concept, let’s implement this capability ourselves. +give it. However, some existing libraries on Crates.io at *https://crates.io/* +can help us with writing a program that accepts command line arguments, but +because you’re just learning this concept, let’s implement this capability +ourselves. ### Reading the Argument Values @@ -104,7 +105,6 @@ adding `use std::env::args` and then calling the function with just `args` because `args` might easily be mistaken for a function that’s defined in the current module. - > ### The `args` Function and Invalid Unicode > > Note that `std::env::args` will panic if any argument contains invalid @@ -490,8 +490,8 @@ trade-off. > make these copies only once, and our filename and query string are very > small. It’s better to have a working program that’s a bit inefficient than to > try to hyperoptimize code on your first pass. As you become more experienced -> with Rust, it’ll be easier to start with the desirable solution, but for now, -> it’s perfectly acceptable to call `clone`. +> with Rust, it’ll be easier to start with the most efficient solution, but for +> now, it’s perfectly acceptable to call `clone`. We’ve updated `main` so it places the instance of `Config` returned by `parse_config` into a variable named `config`, and we updated the code that @@ -729,8 +729,8 @@ Great! This output is much friendlier for our users. Now that we’ve finished refactoring the configuration parsing, let’s turn to the program’s logic. As we stated in “Separation of Concerns for Binary -Projects†on page XX, we’ll extract a function named `run` that will hold all -the logic currently in the `main` function that isn’t involved with setting up +Projectsâ€, we’ll extract a function named `run` that will hold all the logic +currently in the `main` function that isn’t involved with setting up configuration or handling errors. When we’re done, `main` will be concise and easy to verify by inspection, and we’ll be able to write tests for all the other logic. @@ -868,9 +868,9 @@ fn main() { We use `if let` rather than `unwrap_or_else` to check whether `run` returns an `Err` value and call `process::exit(1)` if it does. The `run` function doesn’t return a value that we want to `unwrap` in the same way that `Config::new` -returns the `Config` instance. Because `run` returns a `()` in the success -case, we only care about detecting an error, so we don’t need `unwrap_or_else` -to return the unwrapped value because it would only be `()`. +returns the `Config` instance. Because `run` returns `()` in the success case, +we only care about detecting an error, so we don’t need `unwrap_or_else` to +return the unwrapped value because it would only be `()`. The bodies of the `if let` and the `unwrap_or_else` functions are the same in both cases: we print the error and exit. @@ -890,7 +890,8 @@ Let’s move all the code that isn’t the `main` function from *src/main.rs* to * The `Config::new` function definition 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): +(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: Filename: src/lib.rs @@ -972,10 +973,10 @@ using the Test Driven Development (TDD) process. This software development technique follows these steps: 1. Write a test that fails, and run it to make sure it fails for the reason you -expected. + expected. 2. Write or modify just enough code to make the new test pass. 3. Refactor the code you just added or changed, and make sure the tests -continue to pass. + continue to pass. 4. Repeat from step 1! This process is just one of many ways to write software, but TDD can help drive @@ -995,7 +996,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 will return only the lines from the text that contain the query. -Listing 12-15 shows this test: +Listing 12-15 shows this test, which won't compile yet: Filename: src/lib.rs @@ -1080,15 +1081,15 @@ 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 “Validating -References with Lifetimes†in Chapter 10 on page XX. +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: ``` $ cargo test ---warnings-- Compiling minigrep v0.1.0 (file:///projects/minigrep) +--warnings-- Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs Running target/debug/deps/minigrep-abcabcabc @@ -1298,7 +1299,7 @@ once and have all their searches be case insensitive in that terminal session. We want to add a new `search_case_insensitive` function that we’ll call when 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 +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: @@ -1440,7 +1441,7 @@ won’t compile yet: Filename: src/lib.rs ``` -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(); @@ -1544,7 +1545,7 @@ To an admiring bog! If you’re using PowerShell, you will need to set the environment variable and run the program in two commands rather than one: -```text +``` $ $env.CASE_INSENSITIVE=1 $ cargo run to poem.txt ``` @@ -1569,7 +1570,7 @@ environment variables: check out its documentation to see what is available. At the moment we’re writing all of our output to the terminal using the `println!` function. Most terminals provide two kinds of output: *standard -out**put* (`stdout`) for general information and *standard error* (`stderr`) +output* (`stdout`) for general information and *standard error* (`stderr`) for error messages. This distinction enables users to choose to direct the successful output of a program to a file but still print error messages to the screen. @@ -1687,4 +1688,3 @@ nicely, and be well tested. Next, we’ll explore some Rust features that were influenced by functional languages: closures and iterators. - diff --git a/src/doc/book/second-edition/nostarch/chapter14.md b/src/doc/book/second-edition/nostarch/chapter14.md index 48e1c962c3..08ddf26371 100644 --- a/src/doc/book/second-edition/nostarch/chapter14.md +++ b/src/doc/book/second-edition/nostarch/chapter14.md @@ -1,36 +1,37 @@ +TODO: HASHES FOR SPELLCHECKER HAPPINESS [TOC] -# More about Cargo and Crates.io +# More About Cargo and Crates.io So far we’ve used only the most basic features of Cargo to build, run, and test -our code, but it can do a lot more. Here we’ll go over some of its other, more -advanced features to show you how to: +our code, but it can do a lot more. In this chapter, we’ll discuss some of its +other, more advanced features to show you how to: * Customize your build through release profiles -* Publish libraries on crates.io -* Organize larger projects with workspaces -* Install binaries from crates.io -* Extend Cargo with your own custom commands +* Publish libraries on *https://crates.io/* +* Organize large projects with workspaces +* Install binaries from *https://crates.io/* +* Extend Cargo using custom commands -Cargo can do even more than what we can cover in this chapter too, so for a -full explanation, see its documentation at *https://doc.rust-lang.org/cargo/*. +Cargo can do even more than what we cover in this chapter, so for a full +explanation of all its features, see its documentation at +*https://doc.rust-lang.org/cargo/*. ## Customizing Builds with Release Profiles -In Rust *release profiles* are pre-defined, and customizable, profiles with -different configurations, to allow the programmer more control over various -options for compiling your code. Each profile is configured independently of +In Rust, *release profiles* are predefined and customizable profiles with +different configurations that allow a programmer to have more control over +various options for compiling code. Each profile is configured independently of the others. -Cargo has two main profiles you should know about: the `dev` profile Cargo uses -when you run `cargo build`, and the `release` profile Cargo uses when you run -`cargo build --release`. The `dev` profile is defined with good defaults for -developing, and likewise the `release` profile has good defaults for release -builds. +Cargo has two main profiles: the `dev` profile Cargo uses when you run `cargo +build` and the `release` profile Cargo uses when you run `cargo build +--release`. The `dev` profile is defined with good defaults for developing, and +the `release` profile has good defaults for release builds. -These names may be familiar from the output of your builds, which shows the -profile used in the build: +These profile names might be familiar from the output of your builds, which +shows the profile used in the build: ``` $ cargo build @@ -39,16 +40,14 @@ $ cargo build --release Finished release [optimized] target(s) in 0.0 secs ``` -The “dev†and “release†notifications here indicate that the compiler is using -different profiles. - -### Customizing Release Profiles +The `dev` and `release` shown in this build output indicate that the compiler +is using different profiles. Cargo has default settings for each of the profiles that apply when there aren’t any `[profile.*]` sections in the project’s *Cargo.toml* file. By adding -`[profile.*]` sections for any profile we want to customize, we can choose to -override any subset of the default settings. For example, here are the default -values for the `opt-level` setting for the `dev` and `release` profiles: +`[profile.*]` sections for any profile we want to customize, we can override +any subset of the default settings. For example, here are the default values +for the `opt-level` setting for the `dev` and `release` profiles: Filename: Cargo.toml @@ -60,20 +59,20 @@ opt-level = 0 opt-level = 3 ``` -The `opt-level` setting controls how many optimizations Rust will apply to your -code, with a range of zero to three. Applying more optimizations makes -compilation take longer, so if you’re in development and compiling very often, -you’d want compiling to be fast at the expense of the resulting code running -slower. That’s why the default `opt-level` for `dev` is `0`. When you’re ready -to release, it’s better to spend more time compiling. You’ll only be compiling -in release mode once, and running the compiled program many times, so release -mode trades longer compile time for code that runs faster. That’s why the -default `opt-level` for the `release` profile is `3`. +The `opt-level` setting controls the number of optimizations Rust will apply to +your code with a range of zero to three. Applying more optimizations extends +compiling time, so if you’re in development and compiling your code often, you +want faster compiling even at the expense of the resulting code running 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 and run the compiled program many times, so +release mode trades longer compile time for code that runs faster. That is the +reason the default `opt-level` for the `release` profile is `3`. -We can choose to override any default setting by adding a different value for -them in *Cargo.toml*. If we wanted to use optimization level 1 in the -development profile, for example, we can add these two lines to our project’s -*Cargo.toml*: +We can override any default setting by adding a different value for it in +*Cargo.toml*. For example, if we want to use optimization level 1 in the +development profile, we can add these two lines to our project’s *Cargo.toml* +file: Filename: Cargo.toml @@ -82,40 +81,40 @@ Filename: Cargo.toml opt-level = 1 ``` -This overrides the default setting of `0`. Now when we run `cargo build`, Cargo -will use the defaults for the `dev` profile plus our customization to -`opt-level`. Because we set `opt-level` to `1`, Cargo will apply more -optimizations than the default, but not as many as a release build. +This code overrides the default setting of `0`. Now when we run `cargo` +`build`, Cargo will use the defaults for the `dev` profile plus our +customization to `opt-level`. Because we set `opt-level` to `1`, Cargo will +apply more optimizations than the default, but not as many as a release build. For the full list of configuration options and defaults for each profile, see Cargo’s documentation at *https://doc.rust-lang.org/cargo/*. ## Publishing a Crate to Crates.io -We’ve used packages from crates.io as dependencies of our project, but you can -also share your code for other people to use by publishing your own packages. -Crates.io distributes the source code of your packages, so it primarily hosts -code that’s open source. +We’ve used packages from *https://crates.io/* as dependencies of our project, +but you can also share your code for other people to use by publishing your own +packages. The crate registry at *https://crates.io/* distributes the source +code of your packages, so it primarily hosts code that is open source. Rust and Cargo have features that help make your published package easier for -people to find and use. We’ll talk about some of those features, then cover how -to publish a package. +people to use and to find in the first place. We’ll talk about some of these +features next, and then explain how to publish a package. ### Making Useful Documentation Comments Accurately documenting your packages will help other users know how and when to -use them, so it’s worth spending some time to write documentation. In Chapter -3, we discussed how to comment Rust code with `//`. Rust also has particular -kind of comment for documentation, known conveniently as *documentation +use them, so it’s worth spending time writing documentation. In Chapter 3, we +discussed how to comment Rust code using `//`. Rust also has a particular kind +of comment for documentation, which is known conveniently as *documentation comments*, that will generate HTML documentation. The HTML displays the -contents of documentation comments for public API items, intended for -programmers interested in knowing how to *use* your crate, as opposed to how +contents of documentation comments for public API items intended for +programmers interested in knowing how to *use* your crate as opposed to how your crate is *implemented*. Documentation comments use `///` instead of `//` and support Markdown notation -for formatting the text if you’d like. You place documentation comments just -before the item they are documenting. Listing 14-1 shows documentation comments -for an `add_one` function in a crate named `my_crate`: +for formatting the text if you want to use it. You place documentation comments +just before the item they’re documenting. Listing 14-1 shows documentation +comments for an `add_one` function in a crate named `my_crate`: Filename: src/lib.rs @@ -136,54 +135,54 @@ pub fn add_one(x: i32) -> i32 { Listing 14-1: A documentation comment for a function -Here, we give a description of what the `add_one` function does, then start a -section with the heading “Examplesâ€, and code that demonstrates how to use the -`add_one` function. We can generate the HTML documentation from this -documentation comment by running `cargo doc`. This command runs the `rustdoc` -tool distributed with Rust and puts the generated HTML documentation in the -*target/doc* directory. +Here, we give a description of what the `add_one` function does, start a +section with the heading `Examples`, and then provide code that demonstrates +how to use the `add_one` function. We can generate the HTML documentation from +this documentation comment by running `cargo doc`. This command runs the +`rustdoc` tool distributed with Rust and puts the generated HTML documentation +in the *target/doc* directory. For convenience, running `cargo doc --open` will build the HTML for your current crate’s documentation (as well as the documentation for all of your crate’s dependencies) and open the result in a web browser. Navigate to the -`add_one` function and you’ll see how the text in the documentation comments -gets rendered, shown here in Figure 14-2: +`add_one` function and you’ll see how the text in the documentation comments is +rendered, as shown in Figure 14-1: -Rendered HTML documentation for the `add_one` function of `my_crate` +Rendered HTML documentation for the `add_one` function of `my_crate` -Figure 14-2: HTML documentation for the `add_one` function +Figure 14-1: HTML documentation for the `add_one` function #### Commonly Used Sections -We used the `# Examples` markdown heading in Listing 14-1 to create a section -in the HTML with the title “Examplesâ€. Some other sections that crate authors +We used the `# Examples` Markdown heading in Listing 14-1 to create a section +in the HTML with the title “Examples.†Some other sections that crate authors commonly use in their documentation include: -* **Panics**: The scenarios in which this function could `panic!`. Callers of - this function who don’t want their programs to panic should make sure that - they don’t call this function in these situations. -* **Errors**: If this function returns a `Result`, describing the kinds of +* **Panics**: The scenarios in which the function being documented could + `panic!`. Callers of the function who don’t want their programs to panic + should make sure they don’t call the function in these situations. +* **Errors**: If the function returns a `Result`, describing the kinds of errors that might occur and what conditions might cause those errors to be - returned can be helpful to callers so that they can write code to handle the + returned can be helpful to callers so they can write code to handle the different kinds of errors in different ways. -* **Safety**: If this function is `unsafe` to call (we will discuss unsafety in +* **Safety**: If the function is `unsafe` to call (we discuss unsafety in Chapter 19), there should be a section explaining why the function is unsafe - and covering the invariants that this function expects callers to uphold. + and covering the invariants that the function expects callers to uphold. -Most documentation comment sections don’t need all of these sections, but this -is a good list to check to remind you of the kinds of things that people +Most documentation comment sections don’t need all of these sections, but it’s +a good list to check to remind you of the aspects of your code that people calling your code will be interested in knowing about. #### Documentation Comments as Tests -Adding examples in code blocks in your documentation comments is a way to -clearly demonstrate how to use your library, but it has an additional bonus: -running `cargo test` will run the code examples in your documentation as tests! -Nothing is better than documentation with examples. Nothing is worse than -examples that don’t actually work because the code has changed since the -documentation has been written. Try running `cargo test` with the documentation -for the `add_one` function like in Listing 14-1; you should see a section in -the test results like this: +Adding examples in code blocks in your documentation comments can clearly +demonstrate how to use your library, and doing so has an additional bonus: +running `cargo test` will run the code examples in your documentation as +tests! Nothing is better than documentation with examples. But nothing is worse +than examples that don’t work because the code has changed since the +documentation was written. Run `cargo test` with the documentation for the +`add_one` function from Listing 14-1; you should see a section in the test +results like this: ``` Doc-tests my_crate @@ -191,25 +190,25 @@ the test results like this: running 1 test test src/lib.rs - add_one (line 5) ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Now try changing either the function or the example so that the `assert_eq!` in -the example will panic. Run `cargo test` again, and you’ll see that the doc -tests catch that the example and the code are out of sync from one another! +Now change either the function or the example so the `assert_eq!` in the +example panics. Run `cargo test` again; you’ll see that the doc tests catch +that the example and the code are out of sync from one another! #### Commenting Contained Items -There’s another style of doc comment, `//!`, that adds documentation to the -item that contains the comments, rather than adding documentation to the items -following the comments. These are typically used inside the crate root file +Another style of doc comment, `//!`, adds documentation to the item that +contains the comments rather than adding documentation to the items following +the comments. We typically use these doc comments inside the crate root file (*src/lib.rs* by convention) or inside a module to document the crate or the module as a whole. -For example, if we wanted to add documentation that described the purpose of -the `my_crate` crate that contains the `add_one` function, we can add -documentation comments that start with `//!` to the beginning of *src/lib.rs* -as shown in Listing 14-3: +For example, if we want to add documentation that describes the purpose of the +`my_crate` crate that contains the `add_one` function, we can add documentation +comments that start with `//!` to the beginning of the *src/lib.rs* file, as +shown in Listing 14-2: Filename: src/lib.rs @@ -223,7 +222,7 @@ Filename: src/lib.rs // --snip-- ``` -Listing 14-3: Documentation for the `my_crate` crate as a whole +Listing 14-2: Documentation for the `my_crate` crate as a whole Notice there isn’t any code after the last line that begins with `//!`. Because we started the comments with `//!` instead of `///`, we’re documenting the item @@ -231,48 +230,48 @@ that contains this comment rather than an item that follows this comment. In this case, the item that contains this comment is the *src/lib.rs* file, which is the crate root. These comments describe the entire crate. -If we run `cargo doc --open`, we’ll see these comments displayed on the front +When we run `cargo doc --open`, these comments will display on the front page of the documentation for `my_crate` above the list of public items in the -crate, as shown in Figure 14-4: +crate, as shown in Figure 14-2: -Rendered HTML documentation with a comment for the crate as a whole +Rendered HTML documentation with a comment for the crate as a whole -Figure 14-4: Rendered documentation for `my_crate` including the comment +Figure 14-2: Rendered documentation for `my_crate` including the comment describing the crate as a whole Documentation comments within items are useful for describing crates and -modules especially. Use them to talk about the purpose of the container overall -to help users of your crate understand your organization. +modules especially. Use them to explain the purpose of the container overall to +help your crate users understand your organization. -#### Exporting a Convenient Public API with `pub use` +### Exporting a Convenient Public API with `pub use` -In Chapter 7, we covered how to organize our code into modules with the `mod` -keyword, how to make items public with the `pub` keyword, and how to bring -items into a scope with the `use` keyword. The structure that makes sense to -you while you’re developing a crate may not be very convenient for your users, -however. You may wish to organize your structs in a hierarchy containing -multiple levels, but people that want to use a type you’ve defined deep in the +In Chapter 7, we covered how to organize our code into modules using the `mod` +keyword, how to make items public using the `pub` keyword, and how to bring +items into a scope with the `use` keyword. However, the structure that makes +sense to you while you’re developing a crate might not be very convenient for +your users. You might want to organize your structs in a hierarchy containing +multiple levels, but people who want to use a type you’ve defined deep in the hierarchy might have trouble finding out that those types exist. They might -also be annoyed at having to type `use -my_crate::some_module::another_module::UsefulType;` rather than `use -my_crate::UsefulType;`. +also be annoyed at having to enter `use` +`my_crate::some_module::another_module::UsefulType;` rather than `use` +`my_crate::UsefulType;`. The structure of your public API is a major consideration when publishing a crate. People who use your crate are less familiar with the structure than you -are, and might have trouble finding the pieces they want to use if the module -hierarchy is large. +are and might have difficulty finding the pieces they want to use if your crate +has a large module hierarchy. -The good news is that, if the structure *isn’t* convenient for others to use +The good news is that if the structure *isn’t* convenient for others to use from another library, you don’t have to rearrange your internal organization: -you can choose to re-export items to make a public structure that’s different -to your private structure, using `pub use`. Re-exporting takes a public item in -one location and makes it public in another location as if it was defined in -the other location instead. +instead, you can re-export items to make a public structure that’s different +than your private structure by using `pub use`. Re-exporting takes a public +item in one location and makes it public in another location, as if it was +defined in the other location instead. For example, say we made a library named `art` for modeling artistic concepts. -Within this library is a `kinds` module containing two enums named -`PrimaryColor` and `SecondaryColor` and a `utils` module containing a function -named `mix` as shown in Listing 14-5: +Within this library are two modules: a `kinds` module containing two enums +named `PrimaryColor` and `SecondaryColor`, and a `utils` module containing a +function named `mix`, as shown in Listing 14-3: Filename: src/lib.rs @@ -308,25 +307,25 @@ pub mod utils { } ``` -Listing 14-5: An `art` library with items organized into `kinds` and `utils` +Listing 14-3: An `art` library with items organized into `kinds` and `utils` modules -The front page of the documentation for this crate generated by `cargo doc` -would look like Figure 14-6: +Figure 14-3 shows what the front page of the documentation for this crate +generated by `cargo doc` would look like: -Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules +Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules -Figure 14-6: Front page of the documentation for `art` that lists the `kinds` +Figure 14-3: Front page of the documentation for `art` that lists the `kinds` and `utils` modules Note that the `PrimaryColor` and `SecondaryColor` types aren’t listed on the -front page, nor is the `mix` function. We have to click on `kinds` and `utils` -in order to see them. +front page, nor is the `mix` function. We have to click `kinds` and `utils` to +see them. -Another crate depending on this library would need `use` statements that import -the items from `art` including specifying the module structure that’s currently -defined. Listing 14-7 shows an example of a crate that uses the `PrimaryColor` -and `mix` items from the `art` crate: +Another crate that depends on this library would need `use` statements that +import the items from `art`, including specifying the module structure that’s +currently defined. Listing 14-4 shows an example of a crate that uses the +`PrimaryColor` and `mix` items from the `art` crate: Filename: src/main.rs @@ -343,22 +342,23 @@ fn main() { } ``` -Listing 14-7: A crate using the `art` crate’s items with its internal structure +Listing 14-4: A crate using the `art` crate’s items with its internal structure exported -The author of the code in Listing 14-7 that uses the `art` crate had to figure -out that `PrimaryColor` is in the `kinds` module and `mix` is in the `utils` -module. The module structure of the `art` crate is more relevant to developers -working on the `art` crate than developers using the `art` crate. The internal -structure that organizes parts of the crate into the `kinds` module and the -`utils` module doesn’t add any useful information to someone trying to -understand how to use the `art` crate. The `art` crate’s module structure adds -confusion in having to figure out where to look and inconvenience in having to +The author of the code in Listing 14-4, which uses the `art` crate, had to +figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the +`utils` module. The module structure of the `art` crate is more relevant to +developers working on the `art` crate than developers using the `art` crate. +The internal structure that organizes parts of the crate into the `kinds` +module and the `utils` module doesn’t contain any useful information for +someone trying to understand how to use the `art` crate. Instead, the `art` +crate’s module structure causes confusion because developers have to figure out +where to look, and the structure is inconvenient because developers must specify the module names in the `use` statements. -To remove the internal organization from the public API, we can take the `art` -crate code from Listing 14-5 and add `pub use` statements to re-export the -items at the top level, as shown in Listing 14-8: +To remove the internal organization from the public API, we can modify the +`art` crate code in Listing 14-3 to add `pub use` statements to re-export the +items at the top level, as shown in Listing 14-5: Filename: src/lib.rs @@ -380,20 +380,20 @@ pub mod utils { } ``` -Listing 14-8: Adding `pub use` statements to re-export items +Listing 14-5: Adding `pub use` statements to re-export items -The API documentation generated with `cargo doc` for this crate will now list -and link re-exports on the front page as shown in Figure 14-9, which makes -these types easier to find. +The API documentation that `cargo doc` generates for this crate will now list +and link re-exports on the front page, as shown in Figure 14-4, which makes the +`PrimaryColor` and `SecondaryColor` types and the `mix` function easier to find: -Rendered documentation for the `art` crate with the re-exports on the front page +Rendered documentation for the `art` crate with the re-exports on the front page -Figure 14-9: Front page of the documentation for `art` that lists the +Figure 14-4: The front page of the documentation for `art` that lists the re-exports -Users of the `art` crate can still see and choose to use the internal structure -as in Listing 14-7, or they can use the more convenient structure from Listing -14-8, as shown in Listing 14-10: +The `art` crate users can still see and use the internal structure from Listing +14-3 as demonstrated in Listing 14-4, or they can use the more convenient +structure in Listing 14-5, as shown in Listing 14-6: Filename: src/main.rs @@ -408,51 +408,51 @@ fn main() { } ``` -Listing 14-10: A program using the re-exported items from the `art` crate +Listing 14-6: A program using the re-exported items from the `art` crate In cases where there are many nested modules, re-exporting the types at the top -level with `pub use` can make a big difference in the experience of people who -use the crate. +level with `pub use` can make a significant difference in the experience of +people who use the crate. Creating a useful public API structure is more of an art than a science, and -you can iterate to find the API that works best for your users. Choosing `pub -use` gives you flexibility in how you structure your crate internally, and -decouples that internal structure with what you present to your users. Take a -look at some of the code of crates you’ve installed to see if their internal -structure differs from their public API. +you can iterate to find the API that works best for your users. Choosing `pub` +`use` gives you flexibility in how you structure your crate internally and +decouples that internal structure with what you present to your users. Look at +some of the code of crates you’ve installed to see if their internal structure +differs from their public API. -### Setting up a Crates.io Account +### Setting Up a Crates.io Account -Before you can publish any crates, you need to create an account on crates.io -and get an API token. To do so, visit the home page at *https://crates.io* and -log in via a GitHub account—the GitHub account is a requirement for now, but -the site may support other ways of creating an account in the future. Once -you’re logged in, visit your account settings at *https://crates.io/me* and -retrieve your API key. Then run the `cargo login` command with your API key, -like this: +Before you can publish any crates, you need to create an account on +*https://crates.io/* and get an API token. To do so, visit the home page at +*https://crates.io/* and log in via a GitHub account: the GitHub account is +currently a requirement, but the site might support other ways of creating an +account in the future. Once you’re logged in, visit your account settings at +*https://crates.io/me/* and retrieve your API key. Then run the `cargo` +`login` command with your API key, like this: ``` $ cargo login abcdefghijklmnopqrstuvwxyz012345 ``` This command will inform Cargo of your API token and store it locally in -*~/.cargo/credentials*. Note that this token is a *secret* and should not be -shared with anyone else. If it is shared with anyone for any reason, you should -revoke it and generate a new token on Crates.io. +*~/.cargo/credentials*. Note that this token is a *secret*: do not share it +with anyone else. If you do share it with anyone for any reason, you should +revoke it and generate a new token on *https://crates.io/*. ### Before Publishing a New Crate -Now you have an account, and let’s say you already have a crate you want to -publish. Before publishing, you’ll need to add some metadata to your crate by -adding it to the `[package]` section of the crate’s *Cargo.toml*. +Now that you have an account, let’s say you have a crate you want to publish. +Before publishing, you’ll need to add some metadata to your crate by adding it +to the `[package]` section of the crate’s *Cargo.toml* file. -Your crate will first need a unique name. While you’re working on a crate -locally, you may name a crate whatever you’d like. However, crate names on -Crates.io are allocated on a first-come-first-serve basis. Once a crate name is -taken, no one else may publish a crate with that name. Search for the name -you’d like to use on the site to find out if it has been taken. If it hasn’t, -edit the name in *Cargo.toml* under `[package]` to have the name you want to -use for publishing like so: +Your crate will need a unique name. While you’re working on a crate locally, +you can name a crate whatever you’d like. However, crate names on +*https://crates.io/* are allocated on a first-come, first-served basis. Once +a crate name is taken, no one else can publish a crate with that name. Search +for the name you want to use on the site to find out if it has been used. If it +hasn’t, edit the name in the *Cargo.toml* file under `[package]` to use the +name for publishing, like so: Filename: Cargo.toml @@ -461,8 +461,8 @@ Filename: Cargo.toml name = "guessing_game" ``` -Even if you’ve chosen a unique name, if you try to run `cargo publish` to -publish the crate at this point, you’ll get a warning and then an error: +Even if you’ve chosen a unique name, when you run `cargo publish` to publish +the crate at this point, you’ll get a warning and then an error: ``` $ cargo publish @@ -473,17 +473,17 @@ homepage or repository. error: api errors: missing or empty metadata fields: description, license. ``` -This is because we’re missing some crucial information: a description and -license are required so that people will know what your crate does and under -what terms they may use it. To rectify this error, we need to include this -information in *Cargo.toml*. +The reason is that you’re missing some crucial information: a description and +license are required so people will know what your crate does and under what +terms they can use it. To rectify this error, you need to include this +information in the *Cargo.toml* file. -Make a description that’s just a sentence or two, as it will appear with your -crate in search results and on your crate’s page. For the `license` field, you -need to give a *license identifier value*. The Linux Foundation’s Software -Package Data Exchange (SPDX) at *http://spdx.org/licenses/* lists the -identifiers you can use for this value. For example, to specify that you’ve -licensed your crate using the MIT License, add the `MIT` identifier: +Add a description that is just a sentence or two, because it will appear with +your crate in search results. For the `license` field, you need to give a +*license identifier value*. The Linux Foundation’s Software Package Data +Exchange (SPDX) at *http://spdx.org/licenses/* lists the identifiers you can +use for this value. For example, to specify that you’ve licensed your crate +using the MIT License, add the `MIT` identifier: Filename: Cargo.toml @@ -494,19 +494,19 @@ license = "MIT" ``` If you want to use a license that doesn’t appear in the SPDX, you need to place -the text of that license in a file, include the file in your project, then use -`license-file` to specify the name of that file instead of using the `license` -key. +the text of that license in a file, include the file in your project, and then +use `license-file` to specify the name of that file instead of using the +`license` key. -Guidance on which license is right for your project is out of scope for this -book. Many people in the Rust community choose to license their projects in the -same way as Rust itself, with a dual license of `MIT/Apache-2.0`—this +Guidance on which license is appropriate for your project is beyond the scope +of this book. Many people in the Rust community license their projects in the +same way as Rust by using a dual license of `MIT OR Apache-2.0`, which demonstrates that you can also specify multiple license identifiers separated -by a slash. +by `OR` to have multiple licenses for your project. -So, with a unique name, the version, and author details that `cargo new` added -when you created the crate, your description, and the license you chose added, -the *Cargo.toml* for a project that’s ready to publish might look like this: +With a unique name, the version, the author details that `cargo new` added +when you created the crate, your description, and a license added, the +*Cargo.toml* file for a project that is ready to publish might look like this: Filename: Cargo.toml @@ -516,29 +516,31 @@ name = "guessing_game" version = "0.1.0" authors = ["Your Name "] description = "A fun game where you guess what number the computer has chosen." -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" [dependencies] ``` Cargo’s documentation at *https://doc.rust-lang.org/cargo/* describes other -metadata you can specify to ensure your crate can be discovered and used more +metadata you can specify to ensure others can discover and use your crate more easily! ### Publishing to Crates.io Now that you’ve created an account, saved your API token, chosen a name for your crate, and specified the required metadata, you’re ready to publish! -Publishing a crate uploads a specific version to crates.io for others to use. +Publishing a crate uploads a specific version to *https://crates.io/* for +others to use. -Take care when publishing a crate, because a publish is *permanent*. The +Be careful when publishing a crate because a publish is *permanent*. The version can never be overwritten, and the code cannot be deleted. One major -goal of Crates.io is to act as a permanent archive of code so that builds of -all projects that depend on crates from Crates.io will continue to work. -Allowing deletion of versions would make fulfilling that goal impossible. -However, there is no limit to the number of versions of a crate you can publish. +goal of *https://crates.io/* is to act as a permanent archive of code so that +builds of all projects that depend on crates from *https://crates.io/* will +continue to work. Allowing version deletions would make fulfilling that goal +impossible. However, there is no limit to the number of crate versions you can +publish. -Let’s run the `cargo publish` command again. It should succeed now: +Run the `cargo publish` command again. It should succeed now: ``` $ cargo publish @@ -557,22 +559,22 @@ anyone can easily add your crate as a dependency of their project. ### Publishing a New Version of an Existing Crate When you’ve made changes to your crate and are ready to release a new version, -you change the `version` value specified in your *Cargo.toml* and republish. -Use the Semantic Versioning rules at *http://semver.org/* to decide what an -appropriate next version number is based on the kinds of changes you’ve made. -Then run `cargo publish` to upload the new version. +you change the `version` value specified in your *Cargo.toml* file and +republish. Use the Semantic Versioning rules at *http://semver.org/* to +decide what an appropriate next version number is based on the kinds of changes +you’ve made. Then run `cargo publish` to upload the new version. ### Removing Versions from Crates.io with `cargo yank` -While you can’t remove previous versions of a crate, you can prevent any future -projects from adding them as a new dependency. This is useful when a version of -a crate ends up being broken for one reason or another. For situations such as -this, Cargo supports *yanking* a version of a crate. +Although you can’t remove previous versions of a crate, you can prevent any +future projects from adding them as a new dependency. This is useful when a +crate version is broken for one reason or another. In such situations, Cargo +supports *yanking* a crate version. Yanking a version prevents new projects from starting to depend on that version while allowing all existing projects that depend on it to continue to download and depend on that version. Essentially, a yank means that all projects with a -*Cargo.lock* will not break, while any future *Cargo.lock* files generated will +*Cargo.lock* will not break, and any future *Cargo.lock* files generated will not use the yanked version. To yank a version of a crate, run `cargo yank` and specify which version you @@ -582,100 +584,129 @@ want to yank: $ cargo yank --vers 1.0.1 ``` -You can also undo a yank, and allow projects to start depending on a version -again, by adding `--undo` to the command: +By adding `--undo` to the command, you can also undo a yank and allow projects +to start depending on a version again: ``` $ cargo yank --vers 1.0.1 --undo ``` -A yank *does not* delete any code. The yank feature is not intended for -deleting accidentally uploaded secrets, for example. If that happens, you must +A yank *does not* delete any code. For example, the yank feature is not +intended for deleting accidentally uploaded secrets. If that happens, you must reset those secrets immediately. ## Cargo Workspaces -In Chapter 12, we built a package that included both a binary crate and a -library crate. You may find, as your project develops, that the library crate -continues to get bigger and you want to split your package up further into -multiple library crates. In this situation, Cargo has a feature called +In Chapter 12, we built a package that included a binary crate and a library +crate. As your project develops, you might find that the library crate +continues to get bigger and you want to split up your package further into +multiple library crates. In this situation, Cargo offers a feature called *workspaces* that can help manage multiple related packages that are developed in tandem. -A *workspace* is a set of packages that will all share the same *Cargo.lock* -and output directory. Let’s make a project using a workspace, using trivial -code so we can concentrate on the structure of a workspace. We’ll have a binary -that uses two libraries: one library that will provide an `add_one` function -and a second library that will provide an `add_two` function. These three -crates will all be part of the same workspace. We’ll start by creating a new -crate for the binary: +A *workspace* is a set of packages that share the same *Cargo.lock* and output +directory. Let’s make a project using a workspace and use trivial code so we +can concentrate on the structure of the workspace. There are multiple ways to +structure a workspace; we’re going to show a common way. We’ll have a workspace +containing a binary and two libraries. The binary will provide the main +functionality to be used as a command line tool, and it will depend on the two +libraries. One library will provide an `add_one` function, and a second library +will provide an `add_two` function. These three crates will be part of the same +workspace. We’ll start by creating a new directory for the workspace: ``` -$ cargo new --bin adder - Created binary (application) `adder` project -$ cd adder +$ mkdir add +$ cd add ``` -We need to modify the binary package’s *Cargo.toml* and add a `[workspace]` -section to tell Cargo the `adder` package is a workspace. Add this at the -bottom of the file: +In the *add* directory, create a *Cargo.toml* file. This is the *Cargo.toml* +file that configures the entire workspace. It won’t have a `[package]` section +or metadata we’ve seen in other *Cargo.toml* files. Instead, we’ll start with a +`[workspace]` section and add a member to the workspace by specifying the path +*adder*, which is where we’ll put our binary crate: Filename: Cargo.toml ``` [workspace] + +members = [ + "adder", +] ``` -Like many Cargo features, workspaces support convention over configuration: we -don’t need to add anything more than this to *Cargo.toml* to define our -workspace as long as we follow the convention. +Next, we’ll create the `adder` binary crate by running `cargo new` within the +*add* directory: -### Specifying Workspace Dependencies +``` +$ cargo new --bin adder + Created binary (application) `adder` project +``` -By default, Cargo will include all transitive path dependencies. A *path -dependency* is when any crate, whether in a workspace or not, specifies that it -has a dependency on a crate in a local directory by using the `path` attribute -on the dependency specification in *Cargo.toml*. If a crate has the -`[workspace]` key, or if the crate is itself part of a workspace, and we -specify path dependencies where the paths are subdirectories of the crate’s -directory, those dependent crates will be considered part of the workspace. -Let’s specify in the *Cargo.toml* for the top-level `adder` crate that it will -have a dependency on an `add-one` crate that will be in the `add-one` -subdirectory, by changing *Cargo.toml* to look like this: +At this point, we can build the workspace by running `cargo build`. The files +in your *add* directory should look like this: + +``` +├── Cargo.lock +├── Cargo.toml +├── adder +│ ├── Cargo.toml +│ └── src +│ └── main.rs +└── target +``` + +The workspace has one *target* directory at the top level; the `adder` crate +doesn’t have its own *target* directory. Even if we go into the *adder* +directory and run `cargo build`, the compiled artifacts end up in +*add/target* rather than *add/adder/target*. The crates in a workspace are +meant to depend on each other. If each crate had its own *target* directory, +each crate in the workspace would have to recompile each of the other crates in +the workspace to have the artifacts in its own *target* directory. By sharing +one *target* directory, the crates in the workspace can avoid rebuilding the +other crates in the workspace more than necessary. + +### Creating the Second Crate in the Workspace + +Next, let’s specify another member crate in the workspace. This crate will be +in the *add-one* directory, so change the top-level *Cargo.toml* to have the +*add-one* path as well: Filename: Cargo.toml ``` -[dependencies] -add-one = { path = "add-one" } +[workspace] + +members = [ + "adder", + "add-one", +] ``` -If we add dependencies to *Cargo.toml* that don’t have a `path` specified, -those dependencies will be normal dependencies that aren’t in this workspace -and are assumed to come from Crates.io. - -### Creating the Second Crate in the Workspace - -Next, while in the `adder` directory, generate an `add-one` crate: +Then generate a new library crate named `add-one`: ``` $ cargo new add-one Created library `add-one` project ``` -Your `adder` directory should now have these directories and files: +Your *add* directory should now have these directories and files: ``` +├── Cargo.lock ├── Cargo.toml ├── add-one -│   ├── Cargo.toml -│   └── src -│   └── lib.rs -└── src - └── main.rs +│ ├── Cargo.toml +│ └── src +│ └── lib.rs +├── adder +│ ├── Cargo.toml +│ └── src +│ └── main.rs +└── target ``` -In *add-one/src/lib.rs*, let’s add an `add_one` function: +In the *add-one/src/lib.rs* file, let’s add an `add_one` function: Filename: add-one/src/lib.rs @@ -685,11 +716,28 @@ pub fn add_one(x: i32) -> i32 { } ``` -Open up *src/main.rs* for `adder` and add an `extern crate` line at the top of -the file to bring the new `add-one` library crate into scope. Then change the -`main` function to call the `add_one` function, as in Listing 14-11: +Now that we have a library crate in the workspace, let’s have the binary crate +`adder` depend on the library crate `add-one`. First, we’ll need to add a path +dependency on `add-one` to *adder/Cargo.toml*: -Filename: src/main.rs +Filename: adder/Cargo.toml + +``` +[dependencies] + +add-one = { path = "../add-one" } +``` + +Crates in a workspace don’t have to depend on each other, so we still need to +be explicit about the dependency relationships between the crates in a +workspace. + +Next, let’s use the `add_one` function from the `add-one` crate in the `adder` +crate. Open the *adder/src/main.rs* file and add an `extern crate` line at +the top to bring the new `add-one` library crate into scope. Then change the +`main` function to call the `add_one` function, as in Listing 14-7: + +Filename: adder/src/main.rs ``` extern crate add_one; @@ -700,55 +748,42 @@ fn main() { } ``` -Listing 14-11: Using the `add-one` library crate from the `adder` crate +Listing 14-7: Using the `add-one` library crate from the `adder` crate -Let’s build the `adder` crate by running `cargo build` in the *adder* directory! +Let’s build the workspace by running `cargo build` in the *add* directory! ``` $ cargo build - Compiling add-one v0.1.0 (file:///projects/adder/add-one) - Compiling adder v0.1.0 (file:///projects/adder) + Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs ``` -Note that this builds both the `adder` crate and the `add-one` crate in -*adder/add-one*. Now your *adder* directory should have these files: +To run the binary crate from the top-level *add* directory, we need to specify +which package in the workspace we want to use by using the `-p` argument and +the package name with `cargo run`: ``` -├── Cargo.lock -├── Cargo.toml -├── add-one -│   ├── Cargo.toml -│   └── src -│   └── lib.rs -├── src -│   └── main.rs -└── target +$ cargo run -p adder + Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/adder` +Hello, world! 10 plus one is 11! ``` -The workspace has one *target* directory at the top level; *add-one* doesn’t -have its own *target* directory. Even if we go into the `add-one` directory and -run `cargo build`, the compiled artifacts end up in *adder/target* rather than -*adder/add-one/target*. The crates in a workspace depend on each other. If each -crate had its own *target* directory, each crate in the workspace would have to -recompile each other crate in the workspace in order to have the artifacts in -its own *target* directory. By sharing one *target* directory, the crates in -the workspace can avoid rebuilding the other crates in the workspace more than -necessary. +This runs the code in *adder/src/main.rs*, which depends on the `add-one` crate. #### Depending on an External Crate in a Workspace -Also notice the workspace only has one *Cargo.lock*, rather than having a -top-level *Cargo.lock* and *add-one/Cargo.lock*. This ensures that all crates -are using the same version of all dependencies. If we add the `rand` crate to -both *Cargo.toml* and *add-one/Cargo.toml*, Cargo will resolve both of those to -one version of `rand` and record that in the one *Cargo.lock*. Making all -crates in the workspace use the same dependencies means the crates in the -workspace will always be compatible with each other. Let’s try this out now. - -Let’s add the `rand` crate to the `[dependencies]` section in -*add-one/Cargo.toml* in order to be able to use the `rand` crate in the -`add-one` crate: +Notice that the workspace has only one *Cargo.lock* file at the top level of +the workspace rather than having a *Cargo.lock* in each crate’s directory. This +ensures that all crates are using the same version of all dependencies. If we +add the `rand` crate to the *adder/Cargo.toml* and *add-one/Cargo.toml* +files, Cargo will resolve both of those to one version of `rand` and record +that in the one *Cargo.lock*. Making all crates in the workspace use the same +dependencies means the crates in the workspace will always be compatible with +each other. Let’s add the `rand` crate to the `[dependencies]` section in the +*add-one/Cargo.toml* file to be able to use the `rand` crate in the `add-one` +crate: Filename: add-one/Cargo.toml @@ -758,9 +793,9 @@ Filename: add-one/Cargo.toml rand = "0.3.14" ``` -We can now add `extern crate rand;` to *add-one/src/lib.rs*, and building the -whole workspace by running `cargo build` in the *adder* directory will bring in -and compile the `rand` crate: +We can now add `extern crate rand;` to the *add-one/src/lib.rs* file, and +building the whole workspace by running `cargo build` in the *add* directory +will bring in and compile the `rand` crate: ``` $ cargo build @@ -768,35 +803,36 @@ $ cargo build Downloading rand v0.3.14 --snip-- Compiling rand v0.3.14 - Compiling add-one v0.1.0 (file:///projects/adder/add-one) - Compiling adder v0.1.0 (file:///projects/adder) + Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs ``` -The top level *Cargo.lock* now contains information about `add-one`’s -dependency on `rand`. However, even though `rand` is used somewhere in the +The top-level *Cargo.lock* now contains information about the dependency of +`add-one` on `rand`. However, even though `rand` is used somewhere in the workspace, we can’t use it in other crates in the workspace unless we add -`rand` to their *Cargo.toml* as well. If we add `extern crate rand;` to -*src/main.rs* for the top level `adder` crate, for example, we’ll get an error: +`rand` to their *Cargo.toml* files as well. For example, if we add `extern +crate rand;` to the *adder/src/main.rs* file for the `adder` crate, we’ll get +an error: ``` $ cargo build - Compiling adder v0.1.0 (file:///projects/adder) -error[E0463]: can't find crate for `rand` - --> src/main.rs:1:1 + Compiling adder v0.1.0 (file:///projects/add/adder) +error: use of unstable library feature 'rand': use `rand` from crates.io (see +issue #27703) + --> adder/src/main.rs:1:1 | 1 | extern crate rand; - | ^^^^^^^^^^^^^^^^^^^ can't find crate ``` -To fix this, edit *Cargo.toml* for the top level `adder` crate and indicate -that `rand` is a dependency for that crate as well. Building the `adder` crate -will add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no -additional copies of `rand` will be downloaded. Cargo has ensured for us that -any crate in the workspace using the `rand` crate will be using the same -version. Using the same version of `rand` across the workspace saves space -since we won’t have multiple copies and ensures that the crates in the -workspace will be compatible with each other. +To fix this, edit the *Cargo.toml* file for the `adder` crate and indicate that +`rand` is a dependency for that crate as well. Building the `adder` crate will +add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no +additional copies of `rand` will be downloaded. Cargo has ensured that any +crate in the workspace using the `rand` crate will be using the same version. +Using the same version of `rand` across the workspace saves space because we +won’t have multiple copies and ensures that the crates in the workspace will be +compatible with each other. #### Adding a Test to a Workspace @@ -821,35 +857,21 @@ mod tests { } ``` -Now run `cargo test` in the top-level *adder* directory: +Now run `cargo test` in the top-level *add* directory: ``` $ cargo test - Compiling adder v0.1.0 (file:///projects/adder) + Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs - Running target/debug/adder-f0253159197f7841 - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -Wait a second, zero tests? We just added one! If we look at the output, we can -see that `cargo test` in a workspace only runs tests for the top level crate. -To run tests for all of the crates in the workspace, we need to pass the -`--all` flag: - -``` -$ cargo test --all - Finished dev [unoptimized + debuginfo] target(s) in 0.37 secs - Running target/debug/deps/add_one-abcabcabc + Running target/debug/deps/add_one-f0253159197f7841 running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out - Running target/debug/deps/adder-abcabcabc + Running target/debug/deps/adder-f88af9d2cc175a5e running 0 tests @@ -862,10 +884,15 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -When passing `--all`, `cargo test` will run the tests for all of the crates in -the workspace. We can also choose to run tests for one particular crate in a -workspace from the top level directory by using the `-p` flag and specifying -the name of the crate we want to test: +The first section of the output shows that the `it_works` test in the `add-one` +crate passed. The next section shows that 0 tests were found in the `adder` +crate, and then the last section shows 0 documentation tests were found in the +`add-one` crate. Running `cargo test` in a workspace structured like this one +will run the tests for all the crates in the workspace. + +We can also run tests for one particular crate in a workspace from the +top-level directory by using the `-p` flag and specifying the name of the crate +we want to test: ``` $ cargo test -p add-one @@ -887,40 +914,41 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out This output shows `cargo test` only ran the tests for the `add-one` crate and didn’t run the `adder` crate tests. -If you choose to publish the crates in the workspace to crates.io, each crate -in the workspace will get published separately. The `cargo publish` command -does not have an `--all` flag or a `-p` flag, so it is necessary to change to +If you publish the crates in the workspace to *https://crates.io/*, each crate +in the workspace will need to be published separately. The `cargo publish` +command does not have an `--all` flag or a `-p` flag, so you must change to each crate’s directory and run `cargo publish` on each crate in the workspace -in order to publish them. +to publish them. -Now try adding an `add-two` crate to this workspace in a similar way as the -`add-one` crate for some more practice! +For additional practice, add an `add-two` crate to this workspace in a similar +way as the `add-one` crate! -As your project grows, consider using a workspace: smaller components are -easier to understand individually than one big blob of code. Keeping the crates -in a workspace can make coordination among them easier if they work together -and are often changed at the same time. +As your project grows, consider using a workspace: it’s easier to understand +smaller, individual components than one big blob of code. Keeping the crates in +a workspace can make coordination between them easier if they are often changed +at the same time. ## Installing Binaries from Crates.io with `cargo install` The `cargo install` command allows you to install and use binary crates locally. This isn’t intended to replace system packages; it’s meant to be a convenient way for Rust developers to install tools that others have shared on -crates.io. Only packages that have binary targets can be installed. A binary -target is the runnable program that gets created if the crate has a -*src/main.rs* or another file specified as a binary, as opposed to a library -target that isn’t runnable on its own but is suitable for including within -other programs. Usually, crates have information in the *README* file about -whether a crate is a library, has a binary target, or both. +*https://crates.io/*. You can only install packages that have binary targets. +A binary target is the runnable program that is created if the crate has a +*src/main.rs* file or another file specified as a binary, as opposed to a +library target that isn’t runnable on its own but is suitable for including +within other programs. Usually, crates have information in the *README* file +about whether a crate is a library, has a binary target, or both. -All binaries from `cargo install` are put into the installation root’s *bin* -folder. If you installed Rust using *rustup.rs* and don’t have any custom -configurations, this will be `$HOME/.cargo/bin`. Ensure that directory is in -your `$PATH` to be able to run programs you’ve gotten through `cargo install`. +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 +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`. -For example, we mentioned in Chapter 12 that there’s a Rust implementation of -the `grep` tool for searching files called `ripgrep`. If we want to install -`ripgrep`, we can run: +For example, in Chapter 12 we mentioned that there’s a Rust implementation of +the `grep` tool called `ripgrep` for searching files. If we want to install +`ripgrep`, we can run the following: ``` $ cargo install ripgrep @@ -934,22 +962,23 @@ Updating registry `https://github.com/rust-lang/crates.io-index` The last line of the output shows the location and the name of the installed binary, which in the case of `ripgrep` is `rg`. As long as the installation -directory is in your `$PATH` as mentioned above, you can then run `rg --help` -and start using a faster, rustier tool for searching files! +directory is in your `$PATH`, as mentioned previously, you can then run `rg` +`--help` and start using a faster, rustier tool for searching files! ## Extending Cargo with Custom Commands Cargo is designed so you can extend it with new subcommands without having to -modify Cargo itself. If a binary in your `$PATH` is named `cargo-something`, -you can run it as if it were a Cargo subcommand by running `cargo something`. -Custom commands like this are also listed when you run `cargo --list`. Being -able to `cargo install` extensions and then run them just like the built-in -Cargo tools is a super convenient benefit of Cargo’s design! +modify Cargo. If a binary in your `$PATH` is named `cargo-something`, you can +run it as if it was a Cargo subcommand by running `cargo something`. Custom +commands like this are also listed when you run `cargo --list`. Being able to +use `cargo install` to install extensions and then run them just like the +built-in Cargo tools is a super convenient benefit of Cargo’s design! ## Summary -Sharing code with Cargo and crates.io is part of what makes the Rust ecosystem -useful for many different tasks. Rust’s standard library is small and stable, -but crates are easy to share, use, and improve on a timeline different from the -language itself. Don’t be shy about sharing code that’s useful to you on -Crates.io; it’s likely that it will be useful to someone else as well! +Sharing code with Cargo and *https://crates.io/* is part of what makes the +Rust ecosystem useful for many different tasks. Rust’s standard library is +small and stable, but crates are easy to share, use, and improve on a timeline +different from the language. Don’t be shy about sharing code that’s useful to +you on *https://crates.io/*; it’s likely that it will be useful to someone +else as well! diff --git a/src/doc/book/second-edition/nostarch/chapter15.md b/src/doc/book/second-edition/nostarch/chapter15.md index 8ca50e2b8f..d97f8266fb 100644 --- a/src/doc/book/second-edition/nostarch/chapter15.md +++ b/src/doc/book/second-edition/nostarch/chapter15.md @@ -4,98 +4,57 @@ # Smart Pointers A *pointer* is a general concept for a variable that contains an address in -memory. This address refers to, or “points atâ€, some other data. The most -common kind of pointer in Rust is a *reference*, which we learned about in -Chapter 4. References are indicated by the `&` symbol and borrow the value that -they point to. They don’t have any special abilities other than referring to -data. They also don’t have any overhead, so they’re used the most often. +memory. This address refers to, or “points at,†some other data. The most +common kind of pointer in Rust is a reference, which you learned about in +Chapter 4. References are indicated by the `&` symbol and borrow the value they +point to. They don’t have any special capabilities other than referring to +data. Also, they don’t have any overhead and are the kind of pointer we use +most often. *Smart pointers*, on the other hand, are data structures that act like a -pointer, but they also have additional metadata and capabilities. The concept -of smart pointers isn’t unique to Rust; it originated in C++ and exists in -other languages as well. The different smart pointers defined in Rust’s -standard library provide extra functionality beyond what references provide. -One example that we’ll explore in this chapter is the *reference counting* -smart pointer type, which enables you to have multiple owners of data. The -reference counting smart pointer keeps track of how many owners there are, and -when there aren’t any remaining, the smart pointer takes care of cleaning up -the data. - - - - - - +pointer but also have additional metadata and capabilities. The concept of +smart pointers isn’t unique to Rust: smart pointers originated in C++ and exist +in other languages as well. In Rust, the different smart pointers defined in +the standard library provide extra functionality beyond that provided by +references. One example that we’ll explore in this chapter is the *reference +counting* smart pointer type. This pointer enables you to have multiple owners +of data by keeping track of the number of owners and, when no owners remain, +taking care of cleaning up the data. In Rust, where we have the concept of ownership and borrowing, an additional -difference between references and smart pointers is that references are a kind -of pointer that only borrow data; by contrast, in many cases, smart pointers -*own* the data that they point to. +difference between references and smart pointers is that references are +pointers that only borrow data; in contrast, in many cases, smart pointers +*own* the data they point to. -We’ve actually already encountered a few smart pointers in this book, such as -`String` and `Vec` from Chapter 8, though we didn’t call them smart pointers -at the time. Both these types count as smart pointers because they own some -memory and allow you to manipulate it. They also have metadata (such as their -capacity) and extra capabilities or guarantees (such as `String` ensuring its -data will always be valid UTF-8). +We’ve already encountered a few smart pointers in this book, such as `String` +and `Vec` in Chapter 8, although we didn’t call them smart pointers at the +time. Both these types count as smart pointers because they own some memory and +allow you to manipulate it. They also have metadata (such as their capacity) +and extra capabilities or guarantees (such as with `String` ensuring its data +will always be valid UTF-8). - - - -Smart pointers are usually implemented using structs. The characteristics that -distinguish a smart pointer from an ordinary struct are that smart pointers +Smart pointers are usually implemented using structs. The characteristic that +distinguishes a smart pointer from an ordinary struct is that smart pointers implement the `Deref` and `Drop` traits. The `Deref` trait allows an instance -of the smart pointer struct to behave like a reference so that we can write -code that works with either references or smart pointers. The `Drop` trait -allows us to customize the code that gets run when an instance of the smart -pointer goes out of scope. In this chapter, we’ll be discussing both of those -traits and demonstrating why they’re important to smart pointers. +of the smart pointer struct to behave like a reference so we can write code +that works with either references or smart pointers. The `Drop` trait allows us +to customize the code that is run when an instance of the smart pointer goes +out of scope. In this chapter, we’ll discuss both traits and demonstrate why +they’re important to smart pointers. Given that the smart pointer pattern is a general design pattern used -frequently in Rust, this chapter won’t cover every smart pointer that exists. -Many libraries have their own smart pointers and you can even write some -yourself. We’ll just cover the most common smart pointers from the standard -library: - - - +frequently in Rust, this chapter won’t cover every existing smart pointer. Many +libraries have their own smart pointers, and you can even write your own. We’ll +cover the most common smart pointers in the standard library: * `Box` for allocating values on the heap * `Rc`, a reference counted type that enables multiple ownership * `Ref` and `RefMut`, accessed through `RefCell`, a type that enforces the borrowing rules at runtime instead of compile time - - - -Along the way, we’ll cover the *interior mutability* pattern where an immutable +In addition, we’ll cover the *interior mutability* pattern where an immutable type exposes an API for mutating an interior value. We’ll also discuss -*reference cycles*, how they can leak memory, and how to prevent them. +*reference cycles*: how they can leak memory and how to prevent them. Let’s dive in! @@ -103,41 +62,36 @@ Let’s dive in! The most straightforward smart pointer is a *box*, whose type is written `Box`. Boxes allow you to store data on the heap rather than the stack. What -remains on the stack is the pointer to the heap data. Refer back to Chapter 4 -if you’d like to review the difference between the stack and the heap. +remains on the stack is the pointer to the heap data. Refer to Chapter 4 to +review the difference between the stack and the heap. - - +Boxes don’t have performance overhead, other than storing their data on the +heap instead of on the stack. But they don’t have many extra capabilities +either. You’ll use them most often in these situations: -Boxes don’t have performance overhead other than their data being on the heap -instead of on the stack, but they don’t have a lot of extra abilities either. -They’re most often used in these situations: - -- When you have a type whose size can’t be known at compile time, and you want +* When you have a type whose size can’t be known at compile time, and you want to use a value of that type in a context that needs to know an exact size -- When you have a large amount of data and you want to transfer ownership but +* When you have a large amount of data and you want to transfer ownership but ensure the data won’t be copied when you do so -- When you want to own a value and only care that it’s a type that implements a - particular trait rather than knowing the concrete type itself +* When you want to own a value and only care that it’s a type that implements a + particular trait rather than knowing the concrete type -We’re going to demonstrate the first case in the rest of this section. To -elaborate on the other two situations a bit more: in the second case, +We’ll demonstrate the first situation in this section. But before we do so, +we’ll elaborate on the other two situations a bit more: in the second case, transferring ownership of a large amount of data can take a long time because -the data gets copied around on the stack. To improve performance in this +the data is copied around on the stack. To improve performance in this situation, we can store the large amount of data on the heap in a box. Then, only the small amount of pointer data is copied around on the stack, and the data stays in one place on the heap. The third case is known as a *trait -object*, and Chapter 17 has an entire section devoted just to that topic. So -know that what you learn here will be applied again in Chapter 17! +object*, and Chapter 17 devotes an entire section just to that topic. So what +you learn here you’ll apply again in Chapter 17! ### Using a `Box` to Store Data on the Heap -Before we get into a use case for `Box`, let’s get familiar with the syntax -and how to interact with values stored within a `Box`. +Before we discuss this use case for `Box`, we’ll cover the syntax and how to +interact with values stored within a `Box`. -Listing 15-1 shows how to use a box to store an `i32` on the heap: +Listing 15-1 shows how to use a box to store an `i32` value on the heap: Filename: src/main.rs @@ -153,102 +107,62 @@ Listing 15-1: Storing an `i32` value on the heap using a box We define the variable `b` to have the value of a `Box` that points to the value `5`, which is allocated on the heap. This program will print `b = 5`; in this case, we can access the data in the box in a similar way as we would if -this data was on the stack. Just like any value that has ownership of data, -when a box goes out of scope like `b` does at the end of `main`, it will be -deallocated. The deallocation happens for both the box (stored on the stack) -and the data it points to (stored on the heap). +this data was on the stack. Just like any owned value, when a box goes out of +scope like `b` does at the end of `main`, it will be deallocated. The +deallocation happens for the box (stored on the stack) and the data it points +to (stored on the heap). Putting a single value on the heap isn’t very useful, so you won’t use boxes by -themselves in the way that Listing 15-1 does very often. Having values like a -single `i32` on the stack, where they’re stored by default is more appropriate -in the majority of cases. Let’s get into a case where boxes allow us to define -types that we wouldn’t be allowed to if we didn’t have boxes. - - - +themselves in this way very often. Having values like a single `i32` on the +stack, where they’re stored by default, is more appropriate in the majority of +situations. Let’s look at a case where boxes allow us to define types that we +wouldn’t be allowed to if we didn’t have boxes. ### Boxes Enable Recursive Types - +At compile time, Rust needs to know how much space a type takes up. One type +whose size can’t be known at compile time is a *recursive type*, where a value +can have as part of itself another value of the same type. Because this nesting +of values could theoretically continue infinitely, Rust doesn’t know how much +space a value of a recursive type needs. However, boxes have a known size, so +by inserting a box in a recursive type definition, we can have recursive types. - - +Let’s explore the *cons list*, which is a data type common in functional +programming languages, as an example of a recursive type. The cons list type +we’ll define is straightforward except for the recursion; therefore, the +concepts in the example we’ll work with will be useful any time you get into +more complex situations involving recursive types. -Rust needs to know at compile time how much space a type takes up. One kind of -type whose size can’t be known at compile time is a *recursive type* where a -value can have as part of itself another value of the same type. This nesting -of values could theoretically continue infinitely, so Rust doesn’t know how -much space a value of a recursive type needs. Boxes have a known size, however, -so by inserting a box in a recursive type definition, we are allowed to have -recursive types. +#### More Information About the Cons List -Let’s explore the *cons list*, a data type common in functional programming -languages, to illustrate this concept. The cons list type we’re going to define -is straightforward except for the recursion, so the concepts in this example -will be useful any time you get into more complex situations involving -recursive types. +A *cons list* is a data structure that comes from the Lisp programming language +and its dialects. In Lisp, the `cons` function (short for “construct functionâ€) +constructs a new pair from its two arguments, which usually are a single value +and another pair. These pairs containing pairs form a list. - - +The cons function concept has made its way into more general functional +programming jargon: “to cons x onto y†informally means to construct a new +container instance by putting the element x at the start of this new container, +followed by the container y. -A cons list is a list where each item in the list contains two things: the -value of the current item and the next item. The last item in the list contains -only a value called `Nil` without a next item. +Each item in a cons list contains two elements: the value of the current item +and the next item. The last item in the list contains only a value called `Nil` +without a next item. A cons list is produced by recursively calling the `cons` +function. The canonical name to denote the base case of the recursion is `Nil`. +Note that this is not the same as the “null†or “nil†concept in Chapter 6, +which is an invalid or absent value. -> #### More Information About the Cons List -> -> A *cons list* is a data structure that comes from the Lisp programming -> language and its dialects. In Lisp, the `cons` function (short for “construct -> functionâ€) constructs a new list from its two arguments, which usually are a -> single value and another list. -> -> The cons function concept has made its way into more general functional -> programming jargon; “to cons x onto y†informally means to construct a new -> container instance by putting the element x at the start of this new -> container, followed by the container y. -> -> A cons list is produced by recursively calling the `cons` function. -> The canonical name to denote the base case of the recursion is `Nil`, which -> announces the end of the list. Note that this is not the same as the “null†-> or “nil†concept from Chapter 6, which is an invalid or absent value. +Although functional programming languages use cons lists frequently, it isn’t a +commonly used data structure in Rust. Most of the time when you have a list of +items in Rust, `Vec` is a better choice to use. Other, more complex +recursive data types *are* useful in various situations, but by starting with +the cons list, we can explore how boxes let us define a recursive data type +without much distraction. -Note that while functional programming languages use cons lists frequently, -this isn’t a commonly used data structure in Rust. Most of the time when you -have a list of items in Rust, `Vec` is a better choice. Other, more complex -recursive data types *are* useful in various situations in Rust, but by -starting with the cons list, we can explore how boxes let us define a recursive -data type without much distraction. - - - - -Listing 15-2 contains an enum definition for a cons list. Note that this -won’t compile quite yet because this is type doesn’t have a known size, which +Listing 15-2 contains an enum definition for a cons list. Note that this code +won’t compile yet because the `List` type doesn’t have a known size, which we’ll demonstrate: - - - Filename: src/main.rs ``` @@ -258,22 +172,16 @@ enum List { } ``` -Listing 15-2: The first attempt of defining an enum to represent a cons list +Listing 15-2: The first attempt at defining an enum to represent a cons list data structure of `i32` values -> Note: We’re choosing to implement a cons list that only holds `i32` values -> for the purposes of this example. We could have implemented it using -> generics, as we discussed in Chapter 10, in order to define a cons list type -> that could store values of any type. +> Note: We’re implementing a cons list that only holds `i32` values for the +> purposes of this example. We could have implemented it using generics, as we +> discussed in Chapter 10, to define a cons list type that could store values of +> any type. - - - -Using our cons list type to store the list `1, 2, 3` would look like the code -in Listing 15-3: +Using the `List` type to store the list `1, 2, 3` would look like the code in +Listing 15-3: Filename: src/main.rs @@ -287,21 +195,22 @@ fn main() { Listing 15-3: Using the `List` enum to store the list `1, 2, 3` -The first `Cons` value holds `1` and another `List` value. This `List` -value is another `Cons` value that holds `2` and another `List` value. This +The first `Cons` value holds `1` and another `List` value. This `List` value is +another `Cons` value that holds `2` and another `List` value. This `List` value is one more `Cons` value that holds `3` and a `List` value, which is finally `Nil`, the non-recursive variant that signals the end of the list. -If we try to compile the above code, we get the error shown in Listing 15-4: +If we try to compile the code in Listing 15-3, we get the error shown in +Listing 15-4: ``` error[E0072]: recursive type `List` has infinite size - --> + --> src/main.rs:1:1 | 1 | enum List { | ^^^^^^^^^ recursive type has infinite size 2 | Cons(i32, List), - | --------------- recursive without indirection + | ----- recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable @@ -309,22 +218,14 @@ error[E0072]: recursive type `List` has infinite size Listing 15-4: The error we get when attempting to define a recursive enum - - - -The error says this type ‘has infinite size’. The reason is the way we’ve -defined `List` is with a variant that is recursive: it holds another value of -itself directly. This means Rust can’t figure out how much space it needs in -order to store a `List` value. Let’s break this down a bit: first let’s look at -how Rust decides how much space it needs to store a value of a non-recursive +The error shows this type “has infinite size.†The reason is that we’ve defined +`List` with a variant that is recursive: it holds another value of itself +directly. As a result, Rust can’t figure out how much space it needs to store a +`List` value. Let’s break down why we get this error a bit: first, let’s look +at how Rust decides how much space it needs to store a value of a non-recursive type. -### Computing the Size of a Non-Recursive Type +#### Computing the Size of a Non-Recursive Type Recall the `Message` enum we defined in Listing 6-2 when we discussed enum definitions in Chapter 6: @@ -341,9 +242,9 @@ enum Message { To determine how much space to allocate for a `Message` value, Rust goes through each of the variants to see which variant needs the most space. Rust sees that `Message::Quit` doesn’t need any space, `Message::Move` needs enough -space to store two `i32` values, and so forth. Since only one variant will end -up being used, the most space a `Message` value will need is the space it would -take to store the largest of its variants. +space to store two `i32` values, and so forth. Because only one variant will be +used, the most space a `Message` value will need is the space it would take to +store the largest of its variants. Contrast this to what happens when Rust tries to determine how much space a recursive type like the `List` enum in Listing 15-2 needs. The compiler starts @@ -352,40 +253,38 @@ of type `List`. Therefore, `Cons` needs an amount of space equal to the size of an `i32` plus the size of a `List`. To figure out how much memory the `List` type needs, the compiler looks at the variants, starting with the `Cons` variant. The `Cons` variant holds a value of type `i32` and a value of type -`List`, and this continues infinitely, as shown in Figure 15-5. +`List`, and this process continues infinitely, as shown in Figure 15-1: An infinite Cons list -Figure 15-5: An infinite `List` consisting of infinite `Cons` variants +Figure 15-1: An infinite `List` consisting of infinite `Cons` variants -### Using `Box` to Get a Recursive Type with a Known Size +#### Using `Box` to Get a Recursive Type with a Known Size Rust can’t figure out how much space to allocate for recursively defined types, -so the compiler gives the error in Listing 15-4. The error does include this -helpful suggestion: +so the compiler gives the error in Listing 15-4. But the error does include +this helpful suggestion: ``` -= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to - make `List` representable + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to + make `List` representable ``` In this suggestion, “indirection†means that instead of storing a value -directly, we’re going to store the value indirectly by storing a pointer to -the value instead. +directly, we’ll change the data structure to store the value indirectly by +storing a pointer to the value instead. Because a `Box` is a pointer, Rust always knows how much space a `Box` needs: a pointer’s size doesn’t change based on the amount of data it’s -pointing to. +pointing to. This means we can put a `Box` inside the `Cons` variant instead +of another `List` value directly. The `Box` will point to the next `List` +value that will be on the heap rather than inside the `Cons` variant. +Conceptually, we still have a list, created with lists “holding†other lists, +but this implementation is now more like the items being next to one another +rather than inside one another. -So we can put a `Box` inside the `Cons` variant instead of another `List` value -directly. The `Box` will point to the next `List` value that will be on the -heap, rather than inside the `Cons` variant. Conceptually, we still have a list -created by lists “holding†other lists, but the way this concept is implemented -is now more like the items being next to one another rather than inside one -another. - -We can change the definition of the `List` enum from Listing 15-2 and the usage -of the `List` from Listing 15-3 to the code in Listing 15-6, which will compile: +We can change the definition of the `List` enum in Listing 15-2 and the usage +of the `List` in Listing 15-3 to the code in Listing 15-5, which will compile: Filename: src/main.rs @@ -405,104 +304,59 @@ fn main() { } ``` -Listing 15-6: Definition of `List` that uses `Box` in order to have a known +Listing 15-5: Definition of `List` that uses `Box` in order to have a known size The `Cons` variant will need the size of an `i32` plus the space to store the box’s pointer data. The `Nil` variant stores no values, so it needs less space than the `Cons` variant. We now know that any `List` value will take up the size of an `i32` plus the size of a box’s pointer data. By using a box, we’ve -broken the infinite, recursive chain so the compiler is able to figure out the -size it needs to store a `List` value. Figure 15-7 shows what the `Cons` -variant looks like now: +broken the infinite, recursive chain, so the compiler can figure out the size +it needs to store a `List` value. Figure 15-2 shows what the `Cons` variant +looks like now: A finite Cons list -Figure 15-7: A `List` that is not infinitely sized since `Cons` holds a `Box` - - - +Figure 15-2: A `List` that is not infinitely sized because `Cons` holds a `Box` Boxes only provide the indirection and heap allocation; they don’t have any -other special abilities like those we’ll see with the other smart pointer +other special capabilities, like those we’ll see with the other smart pointer types. They also don’t have any performance overhead that these special -abilities incur, so they can be useful in cases like the cons list where the +capabilities incur, so they can be useful in cases like the cons list where the indirection is the only feature we need. We’ll look at more use cases for boxes in Chapter 17, too. The `Box` type is a smart pointer because it implements the `Deref` trait, which allows `Box` values to be treated like references. When a `Box` value goes out of scope, the heap data that the box is pointing to is cleaned -up as well because of the `Box` type’s `Drop` trait implementation. Let’s -explore these two types in more detail; these traits are going to be even more -important to the functionality provided by the other smart pointer types we’ll -be discussing in the rest of this chapter. +up as well because of the `Drop` trait implementation. Let’s explore these two +traits in more detail. These two traits will be even more important to the +functionality provided by the other smart pointer types we’ll discuss in the +rest of this chapter. - - +## Treating Smart Pointers Like Regular References with the `Deref` Trait -## Treating Smart Pointers like Regular References with the `Deref` Trait +Implementing the `Deref` trait allows us to customize the behavior of the +*dereference operator*, `*` (as opposed to the multiplication or glob +operator). By implementing `Deref` in such a way that a smart pointer can be +treated like a regular reference, we can write code that operates on references +and use that code with smart pointers too. -Implementing `Deref` trait allows us to customize the behavior of the -*dereference operator* `*`(as opposed to the multiplication or glob operator). -By implementing `Deref` in such a way that a smart pointer can be treated like -a regular reference, we can write code that operates on references and use that -code with smart pointers too. - - - - - - - -Let’s first take a look at how `*` works with regular references, then try and -define our own type like `Box` and see why `*` doesn’t work like a -reference. We’ll explore how implementing the `Deref` trait makes it possible -for smart pointers to work in a similar way as references. Finally, we’ll look -at the *deref coercion* feature of Rust and how that lets us work with either -references or smart pointers. +Let’s first look at how `*` works with regular references, and then try to +define our own type like `Box` and see why `*` doesn’t work like a reference +on our newly defined type. We’ll explore how implementing the `Deref` trait +makes it possible for 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. ### Following the Pointer to the Value with `*` - - - - - - A regular reference is a type of pointer, and one way to think of a pointer is -that it’s an arrow to a value stored somewhere else. In Listing 15-8, let’s -create a reference to an `i32` value then use the dereference operator to -follow the reference to the data: +as an arrow to a value stored somewhere else. In Listing 15-6, we create a +reference to an `i32` value and then use the dereference operator to follow the +reference to the data: - - - - - - -Filename: src/main.rs +Filename: src/main.rs ``` fn main() { @@ -514,42 +368,42 @@ fn main() { } ``` -Listing 15-8: Using the dereference operator to follow a reference to an `i32` +Listing 15-6: Using the dereference operator to follow a reference to an `i32` value The variable `x` holds an `i32` value, `5`. We set `y` equal to a reference to `x`. We can assert that `x` is equal to `5`. However, if we want to make an assertion about the value in `y`, we have to use `*y` to follow the reference -to the value that the reference is pointing to (hence *de-reference*). Once we -de-reference `y`, we have access to the integer value `y` is pointing to that -we can compare with `5`. +to the value it’s pointing to (hence *dereference*). Once we dereference `y`, +we have access to the integer value `y` is pointing to that we can compare with +`5`. -If we try to write `assert_eq!(5, y);` instead, we’ll get this compilation +If we tried to write `assert_eq!(5, y);` instead, we would get this compilation error: ``` error[E0277]: the trait bound `{integer}: std::cmp::PartialEq<&{integer}>` is not satisfied - --> :5:19 + --> src/main.rs:6:5 | -5 | if ! ( * left_val == * right_val ) { - | ^^ can't compare `{integer}` with `&{integer}` +6 | assert_eq!(5, y); + | ^^^^^^^^^^^^^^^^^ can't compare `{integer}` with `&{integer}` | = help: the trait `std::cmp::PartialEq<&{integer}>` is not implemented for `{integer}` ``` -Comparing a reference to a number with a number isn’t allowed because they’re -different types. We have to use `*` to follow the reference to the value it’s +Comparing a number and a reference to a number isn’t allowed because they’re +different types. We must use `*` to follow the reference to the value it’s pointing to. ### Using `Box` Like a Reference -We can rewrite the code in Listing 15-8 to use a `Box` instead of a -reference, and the de-reference operator will work the same way as shown in -Listing 15-9: +We can rewrite the code in Listing 15-6 to use a `Box` instead of a +reference, and the dereference operator will work the same way as shown in +Listing 15-7: -Filename: src/main.rs +Filename: src/main.rs ``` fn main() { @@ -561,25 +415,25 @@ fn main() { } ``` -Listing 15-9: Using the dereference operator on a `Box` +Listing 15-7: Using the dereference operator on a `Box` -The only part of Listing 15-8 that we changed was to set `y` to be an instance -of a box pointing to the value in `x` rather than a reference pointing to the -value of `x`. In the last assertion, we can use the dereference operator to -follow the box’s pointer in the same way that we did when `y` was a reference. -Let’s explore what is special about `Box` that enables us to do this by -defining our own box type. +The only difference between Listing 15-7 and Listing 15-6 is that here we set +`y` to be an instance of a box pointing to the value in `x` rather than a +reference pointing to the value of `x`. In the last assertion, we can use the +dereference operator to follow the box’s pointer in the same way that we did +when `y` was a reference. Next, we’ll explore what is special about `Box` +that enables us to use the dereference operator by defining our own box type. ### Defining Our Own Smart Pointer -Let’s build a smart pointer similar to the `Box` type that the standard -library has provided for us, in order to experience that smart pointers don’t -behave like references by default. Then we’ll learn about how to add the -ability to use the dereference operator. +Let’s build a smart pointer similar to the `Box` type provided by the +standard library to experience how smart pointers behave differently to +references by default. Then we’ll look at how to add the ability to use the +dereference operator. -`Box` is ultimately defined as a tuple struct with one element, so Listing -15-10 defines a `MyBox` type in the same way. We’ll also define a `new` -function to match the `new` function defined on `Box`: +The `Box` type is ultimately defined as a tuple struct with one element, so +Listing 15-8 defines a `MyBox` type in the same way. We’ll also define a +`new` function to match the `new` function defined on `Box`: Filename: src/main.rs @@ -593,17 +447,17 @@ impl MyBox { } ``` -Listing 15-10: Defining a `MyBox` type +Listing 15-8: Defining a `MyBox` type -We define a struct named `MyBox` and declare a generic parameter `T`, since we -want our type to be able to hold values of any type. `MyBox` is a tuple struct +We define a struct named `MyBox` and declare a generic parameter `T`, because +we want our type to hold values of any type. The `MyBox` type is a tuple struct with one element of type `T`. The `MyBox::new` function takes one parameter of type `T` and returns a `MyBox` instance that holds the value passed in. -Let’s try adding the code from Listing 15-9 to the code in Listing 15-10 and -changing `main` to use the `MyBox` type we’ve defined instead of `Box`. -The code in Listing 15-11 won’t compile because Rust doesn’t know how to -dereference `MyBox`: +Let’s try adding the `main` function in Listing 15-7 to Listing 15-8 and +changing it to use the `MyBox` type we’ve defined instead of `Box`. The +code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference +`MyBox`: Filename: src/main.rs @@ -617,13 +471,13 @@ fn main() { } ``` -Listing 15-11: Attempting to use `MyBox` in the same way we were able to use -references and `Box` +Listing 15-9: Attempting to use `MyBox` in the same way we used references +and `Box` -The compilation error we get is: +Here’s the resulting compilation error: ``` -error: type `MyBox<{integer}>` cannot be dereferenced +error[E0614]: type `MyBox<{integer}>` cannot be dereferenced --> src/main.rs:14:19 | 14 | assert_eq!(5, *y); @@ -631,23 +485,22 @@ error: type `MyBox<{integer}>` cannot be dereferenced ``` Our `MyBox` type can’t be dereferenced because we haven’t implemented that -ability on our type. To enable dereferencing with the `*` operator, we can +ability on our type. To enable dereferencing with the `*` operator, we implement the `Deref` trait. -### Implementing the `Deref` Trait Defines How To Treat a Type Like a Reference +### Treating a Type Like a Reference by Implementing the `Deref` Trait -As we discussed in Chapter 10, in order to implement a trait, we need to -provide implementations for the trait’s required methods. The `Deref` trait, -provided by the standard library, requires implementing one method named -`deref` that borrows `self` and returns a reference to the inner data. Listing -15-12 contains an implementation of `Deref` to add to the definition of `MyBox`: +As discussed in Chapter 10, to implement a trait, we need to provide +implementations for the trait’s required methods. The `Deref` trait, provided +by the standard library, requires us to implement one method named `deref` that +borrows `self` and returns a reference to the inner data. Listing 15-10 +contains an implementation of `Deref` to add to the definition of `MyBox`: Filename: src/main.rs ``` use std::ops::Deref; -# struct MyBox(T); impl Deref for MyBox { type Target = T; @@ -657,83 +510,68 @@ impl Deref for MyBox { } ``` -Listing 15-12: Implementing `Deref` on `MyBox` +Listing 15-10: Implementing `Deref` on `MyBox` -The `type Target = T;` syntax defines an associated type for this trait to use. -Associated types are a slightly different way of declaring a generic parameter -that you don’t need to worry about too much for now; we’ll cover it in more -detail in Chapter 19. +The `type Target = T;` syntax defines an associated type for the `Deref` trait +to use. Associated types are a slightly different way of declaring a generic +parameter, but you don’t need to worry about them for now; we’ll cover them in +more detail in Chapter 19. - - - -We filled in the body of the `deref` method with `&self.0` so that `deref` -returns a reference to the value we want to access with the `*` operator. The -`main` function from Listing 15-11 that calls `*` on the `MyBox` value now -compiles and the assertions pass! +We fill in the body of the `deref` method with `&self.0` so `deref` returns a +reference to the value we want to access with the `*` operator. The `main` +function in Listing 15-9 that calls `*` on the `MyBox` value now compiles +and the assertions pass! Without the `Deref` trait, the compiler can only dereference `&` references. -The `Deref` trait’s `deref` method gives the compiler the ability to take a -value of any type that implements `Deref` and call the `deref` method in order -to get a `&` reference that it knows how to dereference. +The `deref` method gives the compiler the ability to take a value of any type +that implements `Deref` and call the `deref` method to get a `&` reference that +it knows how to dereference. -When we typed `*y` in Listing 15-11, what Rust actually ran behind the scenes -was this code: +When we entered `*y` in Listing 15-9, behind the scenes Rust actually ran this +code: ``` *(y.deref()) ``` - - - Rust substitutes the `*` operator with a call to the `deref` method and then a -plain dereference so that we don’t have to think about when we have to call the -`deref` method or not. This feature of Rust lets us write code that functions -identically whether we have a regular reference or a type that implements -`Deref`. +plain dereference so as programmers we don’t have to think about whether or not +we need to call the `deref` method. This Rust feature lets us write code that +functions identically whether we have a regular reference or a type that +implements `Deref`. -The reason the `deref` method returns a reference to a value, and why the plain -dereference outside the parentheses in `*(y.deref())` is still necessary, is -because of ownership. If the `deref` method returned the value directly instead -of a reference to the value, the value would be moved out of `self`. We don’t -want to take ownership of the inner value inside `MyBox` in this case and in -most cases where we use the dereference operator. +The reason the `deref` method returns a reference to a value and that the plain +dereference outside the parentheses in `*(y.deref())` is still necessary is due +to the ownership system. If the `deref` method returned the value directly +instead of a reference to the value, the value would be moved out of `self`. We +don’t want to take ownership of the inner value inside `MyBox` in this case +and in most cases where we use the dereference operator. -Note that replacing `*` with a call to the `deref` method and then a call to -`*` happens once, each time we type a `*` in our code. The substitution of `*` -does not recurse infinitely. That’s how we end up with data of type `i32`, -which matches the `5` in the `assert_eq!` in Listing 15-11. +Note that the `*` is replaced with a call to the `deref` method and then a call +to `*` just once, each time we type a `*` in our code. Because the substitution +of `*` does not recurse infinitely, we end up with data of type `i32`, which +matches the `5` in `assert_eq!` in Listing 15-9. ### Implicit Deref Coercions with Functions and Methods - - - *Deref coercion* is a convenience that Rust performs on arguments to functions and methods. Deref coercion converts a reference to a type that implements `Deref` into a reference to a type that `Deref` can convert the original type -into. Deref coercion happens automatically when we pass a reference to a value -of a particular type as an argument to a function or method that doesn’t match -the type of the parameter in the function or method definition, and there’s a -sequence of calls to the `deref` method that will convert the type we provided -into the type that the parameter needs. +into. Deref coercion happens automatically when we pass a reference to a +particular type’s value as an argument to a function or method that doesn’t +match the parameter type in the function or method definition. A sequence of +calls to the `deref` method converts the type we provided into the type the +parameter needs. Deref coercion was added to Rust so that programmers writing function and method calls don’t need to add as many explicit references and dereferences -with `&` and `*`. This feature also lets us write more code that can work for -either references or smart pointers. +with `&` and `*`. The deref coercion feature also lets us write more code that +can work for either references or smart pointers. -To illustrate deref coercion in action, let’s use the `MyBox` type we -defined in Listing 15-10 as well as the implementation of `Deref` that we added -in Listing 15-12. Listing 15-13 shows the definition of a function that has a -string slice parameter: +To see deref coercion in action, let’s use the `MyBox` type we defined in +Listing 15-8 as well as the implementation of `Deref` that we added in Listing +15-10. Listing 15-11 shows the definition of a function that has a string slice +parameter: Filename: src/main.rs @@ -743,115 +581,62 @@ fn hello(name: &str) { } ``` -Listing 15-13: A `hello` function that has the parameter `name` of type `&str` +Listing 15-11: A `hello` function that has the parameter `name` of type `&str` -We can call the `hello` function with a string slice as an argument, like -`hello("Rust");` for example. Deref coercion makes it possible for us to call -`hello` with a reference to a value of type `MyBox`, as shown in -Listing 15-14: +We can call the `hello` function with a string slice as an argument, such as +`hello("Rust");` for example. Deref coercion makes it possible to call `hello` +with a reference to a value of type `MyBox`, as shown in Listing 15-12: Filename: src/main.rs ``` -# use std::ops::Deref; -# -# struct MyBox(T); -# -# impl MyBox { -# fn new(x: T) -> MyBox { -# MyBox(x) -# } -# } -# -# impl Deref for MyBox { -# type Target = T; -# -# fn deref(&self) -> &T { -# &self.0 -# } -# } -# -# fn hello(name: &str) { -# println!("Hello, {}!", name); -# } -# fn main() { let m = MyBox::new(String::from("Rust")); hello(&m); } ``` -Listing 15-14: Calling `hello` with a reference to a `MyBox`, which -works because of deref coercion +Listing 15-12: Calling `hello` with a reference to a `MyBox` value, +which works because of deref coercion Here we’re calling the `hello` function with the argument `&m`, which is a reference to a `MyBox` value. Because we implemented the `Deref` trait -on `MyBox` in Listing 15-12, Rust can turn `&MyBox` into `&String` +on `MyBox` in Listing 15-10, Rust can turn `&MyBox` into `&String` by calling `deref`. The standard library provides an implementation of `Deref` -on `String` that returns a string slice, which we can see in the API -documentation for `Deref`. Rust calls `deref` again to turn the `&String` into -`&str`, which matches the `hello` function’s definition. +on `String` that returns a string slice, which is in the API documentation for +`Deref`. Rust calls `deref` again to turn the `&String` into `&str`, which +matches the `hello` function’s definition. -If Rust didn’t implement deref coercion, in order to call `hello` with a value -of type `&MyBox`, we’d have to write the code in Listing 15-15 instead -of the code in Listing 15-14: +If Rust didn’t implement deref coercion, we would have to write the code in +Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value +of type `&MyBox`: Filename: src/main.rs ``` -# use std::ops::Deref; -# -# struct MyBox(T); -# -# impl MyBox { -# fn new(x: T) -> MyBox { -# MyBox(x) -# } -# } -# -# impl Deref for MyBox { -# type Target = T; -# -# fn deref(&self) -> &T { -# &self.0 -# } -# } -# -# fn hello(name: &str) { -# println!("Hello, {}!", name); -# } -# fn main() { let m = MyBox::new(String::from("Rust")); hello(&(*m)[..]); } ``` -Listing 15-15: The code we’d have to write if Rust didn’t have deref coercion +Listing 15-13: The code we would have to write if Rust didn’t have deref +coercion -The `(*m)` is dereferencing the `MyBox` into a `String`. Then the `&` -and `[..]` are taking a string slice of the `String` that is equal to the whole -string to match the signature of `hello`. The code without deref coercions is -harder to read, write, and understand with all of these symbols involved. Deref -coercion makes it so that Rust takes care of these conversions for us -automatically. +The `(*m)` dereferences the `MyBox` into a `String`. Then the `&` and +`[..]` take a string slice of the `String` that is equal to the whole string to +match the signature of `hello`. The code without deref coercions is harder to +read, write, and understand with all of these symbols involved. Deref coercion +allows Rust to handle these conversions for us automatically. When the `Deref` trait is defined for the types involved, Rust will analyze the -types and use `Deref::deref` as many times as it needs in order to get a -reference to match the parameter’s type. This is resolved at compile time, so -there is no run-time penalty for taking advantage of deref coercion! +types and use `Deref::deref` as many times as necessary to get a reference to +match the parameter’s type. The number of times that `Deref::deref` needs to be +inserted is resolved at compile time, so there is no runtime penalty for taking +advantage of deref coercion! ### How Deref Coercion Interacts with Mutability - - - Similar to how we use the `Deref` trait to override `*` on immutable references, Rust provides a `DerefMut` trait for overriding `*` on mutable references. @@ -859,36 +644,26 @@ references. Rust does deref coercion when it finds types and trait implementations in three cases: - - +* From `&T` to `&U` when `T: Deref` +* From `&mut T` to `&mut U` when `T: DerefMut` +* From `&mut T` to `&U` when `T: Deref` -* From `&T` to `&U` when `T: Deref`. -* From `&mut T` to `&mut U` when `T: DerefMut`. -* From `&mut T` to `&U` when `T: Deref`. - -The first two cases are the same except for mutability. The first case says +The first two cases are the same except for mutability. The first case states that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can get a `&U` transparently. The second case states that the same deref coercion happens for mutable references. -The last case is trickier: Rust will also coerce a mutable reference to an -immutable one. The reverse is *not* possible though: immutable references will -never coerce to mutable ones. Because of the borrowing rules, if you have a -mutable reference, that mutable reference must be the only reference to that +The third case is trickier: Rust will also coerce a mutable reference to an +immutable one. But the reverse is *not* possible: immutable references will +never coerce to mutable references. Because of the borrowing rules, if you have +a mutable reference, that mutable reference must be the only reference to that data (otherwise, the program wouldn’t compile). Converting one mutable reference to one immutable reference will never break the borrowing rules. Converting an immutable reference to a mutable reference would require that -there was only one immutable reference to that data, and the borrowing rules +there is only one immutable reference to that data, and the borrowing rules don’t guarantee that. Therefore, Rust can’t make the assumption that converting an immutable reference to a mutable reference is possible. - - - ## The `Drop` Trait Runs Code on Cleanup The second trait important to the smart pointer pattern is `Drop`, which lets @@ -897,49 +672,27 @@ provide an implementation for the `Drop` trait on any type, and the code we specify can be used to release resources like files or network connections. We’re introducing `Drop` in the context of smart pointers because the functionality of the `Drop` trait is almost always used when implementing a -smart pointer. For example, `Box` customizes `Drop` in order to deallocate -the space on the heap that the box points to. +smart pointer. For example, `Box` customizes `Drop` to deallocate the space +on the heap that the box points to. In some languages, the programmer must call code to free memory or resources every time they finish using an instance of a smart pointer. If they forget, the system might become overloaded and crash. In Rust, we can specify that a particular bit of code should be run whenever a value goes out of scope, and -the compiler will insert this code automatically. - - - - -This means we don’t need to be careful about placing clean up code everywhere -in a program that an instance of a particular type is finished with, but we -still won’t leak resources! +the compiler will insert this code automatically. As a result, we don’t need to +be careful about placing cleanup code everywhere in a program that an instance +of a particular type is finished with, but we still won’t leak resources! We specify the code to run when a value goes out of scope by implementing the `Drop` trait. The `Drop` trait requires us to implement one method named `drop` -that takes a mutable reference to `self`. In order to be able to see when Rust -calls `drop`, let’s implement `drop` with `println!` statements for now. +that takes a mutable reference to `self`. To see when Rust calls `drop`, let’s +implement `drop` with `println!` statements for now. - - - -Listing 15-8 shows a `CustomSmartPointer` struct whose only custom -functionality is that it will print out `Dropping CustomSmartPointer!` when the -instance goes out of scope. This will demonstrate when Rust runs the `drop` +Listing 15-14 shows a `CustomSmartPointer` struct whose only custom +functionality is that it will print `Dropping CustomSmartPointer!` when the +instance goes out of scope. This example demonstrates when Rust runs the `drop` function: - - - Filename: src/main.rs ``` @@ -960,23 +713,18 @@ fn main() { } ``` -Listing 15-8: A `CustomSmartPointer` struct that implements the `Drop` trait, -where we would put our clean up code. +Listing 15-14: A `CustomSmartPointer` struct that implements the `Drop` trait +where we would put our cleanup code The `Drop` trait is included in the prelude, so we don’t need to import it. We -implement the `Drop` trait on `CustomSmartPointer`, and provide an +implement the `Drop` trait on `CustomSmartPointer` and provide an implementation for the `drop` method that calls `println!`. The body of the -`drop` function is where you’d put any logic that you wanted to run when an -instance of your type goes out of scope. We’re choosing to print out some text -here in order to demonstrate when Rust will call `drop`. +`drop` function is where you would place any logic that you wanted to run when +an instance of your type goes out of scope. We’re printing some text here to +demonstrate when Rust will call `drop`. - - - -In `main`, we create a new instance of `CustomSmartPointer` and then print out -`CustomSmartPointer created.`. At the end of `main`, our instance of +In `main`, we create two instances of `CustomSmartPointer` and then print +`CustomSmartPointers created.`. At the end of `main`, our instance of `CustomSmartPointer` will go out of scope, and Rust will call the code we put in the `drop` method, printing our final message. Note that we didn’t need to call the `drop` method explicitly. @@ -991,34 +739,26 @@ Dropping CustomSmartPointer with data `my stuff`! Rust automatically called `drop` for us when our instance went out of scope, calling the code we specified. Variables are dropped in the reverse order of -the order in which they were created, so `d` was dropped before `c`. This is -just to give you a visual guide to how the drop method works, but usually you -would specify the cleanup code that your type needs to run rather than a print -message. +the order in which they were created, so `d` was dropped before `c`. This +example just gives you a visual guide to how the `drop` method works, but +usually you would specify the cleanup code that your type needs to run rather +than a print message. - - +### Dropping a Value Early with `std::mem::drop` -#### Dropping a Value Early with `std::mem::drop` +Unfortunately, it’s not straightforward to disable the automatic `drop` +functionality. Disabling `drop` isn’t usually necessary; the whole point of the +`Drop` trait is that it’s taken care of automatically. Occasionally, you might +want to clean up a value early. One example is when using smart pointers that +manage locks: you might want to force the `drop` method that releases the lock +to run so other code in the same scope can acquire the lock. Rust doesn’t let +us call the `Drop` trait’s `drop` method manually; instead we have to call the +`std::mem::drop` function provided by the standard library if we want to force +a value to be dropped before the end of its scope. - - - -Rust inserts the call to `drop` automatically when a value goes out of scope, -and it’s not straightforward to disable this functionality. Disabling `drop` -isn’t usually necessary; the whole point of the `Drop` trait is that it’s taken -care of automatically for us. Occasionally you may find that you want to clean -up a value early. One example is when using smart pointers that manage locks; -you may want to force the `drop` method that releases the lock to run so that -other code in the same scope can acquire the lock. First, let’s see what -happens if we try to call the `Drop` trait’s `drop` method ourselves by -modifying the `main` function from Listing 15-8 as shown in Listing 15-9: - - - +Let’s see what happens when we try to call the `Drop` trait’s `drop` method +manually by modifying the `main` function in Listing 15-14, as shown in Listing +15-15: Filename: src/main.rs @@ -1031,52 +771,42 @@ fn main() { } ``` -Listing 15-9: Attempting to call the `drop` method from the `Drop` trait +Listing 15-15: Attempting to call the `drop` method from the `Drop` trait manually to clean up early -If we try to compile this, we’ll get this error: +When we try to compile this code, we’ll get this error: ``` error[E0040]: explicit use of destructor method - --> src/main.rs:15:7 + --> src/main.rs:14:7 | -15 | c.drop(); +14 | c.drop(); | ^^^^ explicit destructor calls not allowed ``` -This error message says we’re not allowed to explicitly call `drop`. The error -message uses the term *destructor*, which is the general programming term for a -function that cleans up an instance. A *destructor* is analogous to a +This error message states that we’re not allowed to explicitly call `drop`. The +error message uses the term *destructor*, which is the general programming term +for a function that cleans up an instance. A *destructor* is analogous to a *constructor* that creates an instance. The `drop` function in Rust is one particular destructor. Rust doesn’t let us call `drop` explicitly because Rust would still -automatically call `drop` on the value at the end of `main`, and this would be -a *double free* error since Rust would be trying to clean up the same value +automatically call `drop` on the value at the end of `main`. This would be a +*double free* error because Rust would be trying to clean up the same value twice. -Because we can’t disable the automatic insertion of `drop` when a value goes -out of scope, and we can’t call the `drop` method explicitly, if we need to -force a value to be cleaned up early, we can use the `std::mem::drop` function. +We can’t disable the automatic insertion of `drop` when a value goes out of +scope, and we can’t call the `drop` method explicitly. So, if we need to force +a value to be cleaned up early, we can use the `std::mem::drop` function. The `std::mem::drop` function is different than the `drop` method in the `Drop` trait. We call it by passing the value we want to force to be dropped early as -an argument. `std::mem::drop` is in the prelude, so we can modify `main` from -Listing 15-8 to call the `drop` function as shown in Listing 15-10: +an argument. The function is in the prelude, so we can modify `main` in Listing +15-14 to call the `drop` function, as shown in Listing 15-16: Filename: src/main.rs ``` -# struct CustomSmartPointer { -# data: String, -# } -# -# impl Drop for CustomSmartPointer { -# fn drop(&mut self) { -# println!("Dropping CustomSmartPointer!"); -# } -# } -# fn main() { let c = CustomSmartPointer { data: String::from("some data") }; println!("CustomSmartPointer created."); @@ -1085,97 +815,84 @@ fn main() { } ``` -Listing 15-10: Calling `std::mem::drop` to explicitly drop a value before it +Listing 15-16: Calling `std::mem::drop` to explicitly drop a value before it goes out of scope Running this code will print the following: ``` CustomSmartPointer created. -Dropping CustomSmartPointer! +Dropping CustomSmartPointer with data `some data`! CustomSmartPointer dropped before the end of main. ``` - - +The text ```Dropping CustomSmartPointer with data `some data`!``` is printed +between the `CustomSmartPointer created.` and `CustomSmartPointer dropped +before the end of main.` text, showing that the `drop` method code is called to +drop `c` at that point. -The `Dropping CustomSmartPointer!` is printed between `CustomSmartPointer -created.` and `CustomSmartPointer dropped before the end of main.`, showing -that the `drop` method code is called to drop `c` at that point. - - - - -Code specified in a `Drop` trait implementation can be used in many ways to -make cleanup convenient and safe: we could use it to create our own memory -allocator, for instance! With the `Drop` trait and Rust’s ownership system, you -don’t have to remember to clean up after yourself, Rust takes care of it -automatically. +We can use code specified in a `Drop` trait implementation in many ways to make +cleanup convenient and safe: for instance, we could use it to create our own +memory allocator! With the `Drop` trait and Rust’s ownership system, we don’t +have to remember to clean up because Rust does it automatically. We also don’t have to worry about accidentally cleaning up values still in use because that would cause a compiler error: the ownership system that makes sure -references are always valid will also make sure that `drop` only gets called -once when the value is no longer being used. +references are always valid also ensures that `drop` gets called only once when +the value is no longer being used. -Now that we’ve gone over `Box` and some of the characteristics of smart -pointers, let’s talk about a few other smart pointers defined in the standard +Now that we’ve examined `Box` and some of the characteristics of smart +pointers, let’s look at a few other smart pointers defined in the standard library. ## `Rc`, the Reference Counted Smart Pointer In the majority of cases, ownership is clear: you know exactly which variable -owns a given value. However, there are cases when a single value may have -multiple owners. For example, in graph data structures, multiple edges may +owns a given value. However, there are cases when a single value might have +multiple owners. For example, in graph data structures, multiple edges might point to the same node, and that node is conceptually owned by all of the edges that point to it. A node shouldn’t be cleaned up unless it doesn’t have any edges pointing to it. - - +To enable multiple ownership, Rust has a type called `Rc`. Its name is an +abbreviation for *reference counting*, which keeps track of the number of +references to a value to know whether or not a value is still in use. If there +are zero references to a value, the value can be cleaned up without any +references becoming invalid. -In order to enable multiple ownership, Rust has a type called `Rc`. Its name -is an abbreviation for reference counting. *Reference counting* means keeping -track of the number of references to a value in order to know if a value is -still in use or not. If there are zero references to a value, the value can be -cleaned up without any references becoming invalid. - -Imagine it like a TV in a family room. When one person enters to watch TV, they -turn it on. Others can come into the room and watch the TV. When the last -person leaves the room, they turn the TV off because it’s no longer being used. -If someone turns the TV off while others are still watching it, there’d be +Imagine `Rc` as a TV in a family room. When one person enters to watch TV, +they turn it on. Others can come into the room and watch the TV. When the last +person leaves the room, they turn off the TV because it’s no longer being used. +If someone turns off the TV while others are still watching it, there would be uproar from the remaining TV watchers! -`Rc` is used when we want to allocate some data on the heap for multiple -parts of our program to read, and we can’t determine at compile time which part -will finish using the data last. If we did know which part would finish last, -we could just make that the owner of the data and the normal ownership rules -enforced at compile time would kick in. +We use the `Rc` type when we want to allocate some data on the heap for +multiple parts of our program to read, and we can’t determine at compile time +which part will finish using the data last. If we knew which part would finish +last, we could just make that part the data’s owner and the normal ownership +rules enforced at compile time would take effect. -Note that `Rc` is only for use in single-threaded scenarios; Chapter 16 on -concurrency will cover how to do reference counting in multithreaded programs. +Note that `Rc` is only for use in single-threaded scenarios. When we discuss +concurrency in Chapter 16, we’ll cover how to do reference counting in +multithreaded programs. ### Using `Rc` to Share Data -Let’s return to our cons list example from Listing 15-6, as we defined it using -`Box`. This time, we want to create two lists that both share ownership of a -third list, which conceptually will look something like Figure 15-11: +Let’s return to our cons list example in Listing 15-5. Recall that we defined +it using `Box`. This time, we’ll create two lists that both share ownership +of a third list, which conceptually will look similar to Figure 15-3: Two lists that share ownership of a third list -Figure 15-11: Two lists, `b` and `c`, sharing ownership of a third list, `a` +Figure 15-3: Two lists, `b` and `c`, sharing ownership of a third list, `a` -We’ll create list `a` that contains 5 and then 10, then make two more lists: -`b` that starts with 3 and `c` that starts with 4. Both `b` and `c` lists will -then continue on to the first `a` list containing 5 and 10. In other words, -both lists will try to share the first list containing 5 and 10. +We’ll create list `a` that contains 5 and then 10. Then we’ll make two more +lists: `b` that starts with 3 and `c` that starts with 4. Both `b` and `c` +lists will then continue on to the first `a` list containing 5 and 10. In other +words, both lists will share the first list containing 5 and 10. -Trying to implement this using our definition of `List` with `Box` won’t -work, as shown in Listing 15-12: +Trying to implement this scenario using our definition of `List` with `Box` +won’t work, as shown in Listing 15-17: Filename: src/main.rs @@ -1196,10 +913,10 @@ fn main() { } ``` -Listing 15-12: Demonstrating we’re not allowed to have two lists using `Box` +Listing 15-17: Demonstrating we’re not allowed to have two lists using `Box` that try to share ownership of a third list -If we compile this, we get this error: +When we compile this code, we get this error: ``` error[E0382]: use of moved value: `a` @@ -1210,8 +927,8 @@ error[E0382]: use of moved value: `a` 13 | let c = Cons(4, Box::new(a)); | ^ value used here after move | - = note: move occurs because `a` has type `List`, which does not - implement the `Copy` trait + = note: move occurs because `a` has type `List`, which does not implement + the `Copy` trait ``` The `Cons` variants own the data they hold, so when we create the `b` list, `a` @@ -1219,27 +936,22 @@ is moved into `b` and `b` owns `a`. Then, when we try to use `a` again when creating `c`, we’re not allowed to because `a` has been moved. We could change the definition of `Cons` to hold references instead, but then -we’d have to specify lifetime parameters. By specifying lifetime parameters, -we’d be specifying that every element in the list will live at least as long as -the list itself. The borrow checker wouldn’t let us compile `let a = Cons(10, -&Nil);` for example, since the temporary `Nil` value would be dropped before -`a` could take a reference to it. +we would have to specify lifetime parameters. By specifying lifetime +parameters, we would be specifying that every element in the list will live at +least as long as the entire list. The borrow checker wouldn’t let us compile +`let a = Cons(10, &Nil);` for example, because the temporary `Nil` value would +be dropped before `a` could take a reference to it. Instead, we’ll change our definition of `List` to use `Rc` in place of -`Box` as shown here in Listing 15-13. Each `Cons` variant now holds a value -and an `Rc` pointing to a `List`. When we create `b`, instead of taking -ownership of `a`, we clone the `Rc` that `a` is holding, which increases the -number of references from 1 to 2 and lets `a` and `b` share ownership of the -data in that `Rc`. We also clone `a` when creating `c`, which increases the -number of references from 2 to 3. Every time we call `Rc::clone`, the reference -count to the data within the `Rc` is increased, and the data won’t be cleaned -up unless there are zero references to it: - - - +`Box`, as shown in Listing 15-18. Each `Cons` variant will now hold a value +and an `Rc` pointing to a `List`. When we create `b`, instead of taking +ownership of `a`, we’ll clone the `Rc` that `a` is holding, which +increases the number of references from one to two and lets `a` and `b` share +ownership of the data in that `Rc`. We’ll also clone `a` when creating +`c`, which increases the number of references from two to three. Every time we +call `Rc::clone`, the reference count to the data within the `Rc` will +increase, and the data won’t be cleaned up unless there are zero references to +it: Filename: src/main.rs @@ -1259,61 +971,41 @@ fn main() { } ``` -Listing 15-13: A definition of `List` that uses `Rc` +Listing 15-18: A definition of `List` that uses `Rc` -We need to add a `use` statement to bring `Rc` into scope because it’s not in -the prelude. In `main`, we create the list holding 5 and 10 and store it in a -new `Rc` in `a`. Then when we create `b` and `c`, we call the `Rc::clone` -function and pass a reference to the `Rc` in `a` as an argument. +We need to add a `use` statement to bring `Rc` into scope because it’s not +in the prelude. In `main`, we create the list holding 5 and 10 and store it in +a new `Rc` in `a`. Then when we create `b` and `c`, we call the +`Rc::clone` function and pass a reference to the `Rc` in `a` as an +argument. -We could have called `a.clone()` rather than `Rc::clone(&a)`, but Rust -convention is to use `Rc::clone` in this case. The implementation of `clone` -doesn’t make a deep copy of all the data like most types’ implementations of -`clone` do. `Rc::clone` only increments the reference count, which doesn’t take -very much time. Deep copies of data can take a lot of time, so by using -`Rc::clone` for reference counting, we can visually distinguish between the -deep copy kinds of clones that might have a large impact on runtime performance -and memory usage and the types of clones that increase the reference count that -have a comparatively small impact on runtime performance and don’t allocate new -memory. +We could have called `a.clone()` rather than `Rc::clone(&a)`, but Rust’s +convention is to use `Rc::clone` in this case. The implementation of +`Rc::clone` doesn’t make a deep copy of all the data like most types’ +implementations of `clone` do. The call to `Rc::clone` only increments the +reference count, which doesn’t take much time. Deep copies of data can take a +lot of time. By using `Rc::clone` for reference counting, we can visually +distinguish between the deep copy kinds of clones and the kinds of clones that +increase the reference count. When looking for performance problems in the +code, we only need to consider the deep copy clones and can disregard calls to +`Rc::clone`. ### Cloning an `Rc` Increases the Reference Count -Let’s change our working example from Listing 15-13 so that we can see the -reference counts changing as we create and drop references to the `Rc` in `a`. +Let’s change our working example in Listing 15-18 so we can see the reference +counts changing as we create and drop references to the `Rc` in `a`. - - - -In Listing 15-14, we’ll change `main` so that it has an inner scope around list -`c`, so that we can see how the reference count changes when `c` goes out of -scope. At each point in the program where the reference count changes, we’ll -print out the reference count, which we can get by calling the -`Rc::strong_count` function. We’ll talk about why this function is named -`strong_count` rather than `count` in the section later in this chapter about -preventing reference cycles. - - - +In Listing 15-19, we’ll change `main` so it has an inner scope around list `c`; +then we can see how the reference count changes when `c` goes out of scope. At +each point in the program where the reference count changes, we’ll print the +reference count, which we can get by calling the `Rc::strong_count` function. +This function is named `strong_count` rather than `count` because the `Rc` +type also has a `weak_count`; we’ll see what `weak_count` is used for in the +“Preventing Reference Cycles†section. Filename: src/main.rs ``` -# enum List { -# Cons(i32, Rc), -# Nil, -# } -# -# use List::{Cons, Nil}; -# use std::rc::Rc; -# fn main() { let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); println!("count after creating a = {}", Rc::strong_count(&a)); @@ -1327,9 +1019,9 @@ fn main() { } ``` -Listing 15-14: Printing out the reference count +Listing 15-19: Printing the reference count -This will print out: +This code prints the following: ``` count after creating a = 1 @@ -1338,129 +1030,98 @@ count after creating c = 3 count after c goes out of scope = 2 ``` - - - -We’re able to see that the `Rc` in `a` has an initial reference count of one, +We can see that the `Rc` in `a` has an initial reference count of one; then each time we call `clone`, the count goes up by one. When `c` goes out of scope, the count goes down by one. We don’t have to call a function to decrease the reference count like we have to call `Rc::clone` to increase the reference -count; the implementation of the `Drop` trait decreases the reference count -automatically when an `Rc` value goes out of scope. +count: the implementation of the `Drop` trait decreases the reference count +automatically when an `Rc` value goes out of scope. -What we can’t see from this example is that when `b` and then `a` go out of -scope at the end of `main`, the count is then 0, and the `Rc` is cleaned up -completely at that point. Using `Rc` allows a single value to have multiple -owners, and the count will ensure that the value remains valid as long as any -of the owners still exist. +What we can’t see in this example is that when `b` and then `a` go out of scope +at the end of `main`, the count is then 0, and the `Rc` is cleaned up +completely at that point. Using `Rc` allows a single value to have +multiple owners, and the count ensures that the value remains valid as long as +any of the owners still exist. -`Rc` allows us to share data between multiple parts of our program for -reading only, via immutable references. If `Rc` allowed us to have multiple -mutable references too, we’d be able to violate one of the the borrowing rules -that we discussed in Chapter 4: multiple mutable borrows to the same place can -cause data races and inconsistencies. But being able to mutate data is very -useful! In the next section, we’ll discuss the interior mutability pattern and -the `RefCell` type that we can use in conjunction with an `Rc` to work -with this restriction on immutability. +Via immutable references, `Rc` allows us to share data between multiple +parts of our program for reading only. If `Rc` allowed us to have multiple +mutable references too, we might violate one of the borrowing rules discussed +in Chapter 4: multiple mutable borrows to the same place can cause data races +and inconsistencies. But being able to mutate data is very useful! In the next +section, we’ll discuss the interior mutability pattern and the `RefCell` +type that we can use in conjunction with an `Rc` to work with this +immutability restriction. ## `RefCell` and the Interior Mutability Pattern - - +*Interior mutability* is a design pattern in Rust that allows you to mutate +data even when there are immutable references to that data: normally, this +action is disallowed by the borrowing rules. To do so, the pattern uses +`unsafe` code inside a data structure to bend Rust’s usual rules that govern +mutation and borrowing. We haven’t yet covered unsafe code; we will in Chapter +19. We can use types that use the interior mutability pattern when we can +ensure that the borrowing rules will be followed at runtime, even though the +compiler can’t guarantee that. The `unsafe` code involved is then wrapped in a +safe API, and the outer type is still immutable. - - - -*Interior mutability* is a design pattern in Rust for allowing you to mutate -data even when there are immutable references to that data, normally disallowed -by the borrowing rules. To do so, the pattern uses `unsafe` code inside a data -structure to bend Rust’s usual rules around mutation and borrowing. We haven’t -yet covered unsafe code; we will in Chapter 19. We can choose to use types that -make use of the interior mutability pattern when we can ensure that the -borrowing rules will be followed at runtime, even though the compiler can’t -ensure that. The `unsafe` code involved is then wrapped in a safe API, and the -outer type is still immutable. - -Let’s explore this by looking at the `RefCell` type that follows the +Let’s explore this concept by looking at the `RefCell` type that follows the interior mutability pattern. ### Enforcing Borrowing Rules at Runtime with `RefCell` Unlike `Rc`, the `RefCell` type represents single ownership over the data it holds. So, what makes `RefCell` different than a type like `Box`? -Let’s recall the borrowing rules we learned in Chapter 4: +Recall the borrowing rules you learned in Chapter 4: -1. At any given time, you can have *either* but not both of: - * One mutable reference. - * Any number of immutable references. -2. References must always be valid. +* At any given time, you can have *either* but not both of the following: one + mutable reference or any number of immutable references. +* References must always be valid. With references and `Box`, the borrowing rules’ invariants are enforced at compile time. With `RefCell`, these invariants are enforced *at runtime*. With references, if you break these rules, you’ll get a compiler error. With -`RefCell`, if you break these rules, you’ll get a `panic!`. +`RefCell`, if you break these rules, your program will `panic!` and exit. - - +The advantages of checking the borrowing rules at compile time are that errors +will be caught sooner in the development process, and there is no impact on +runtime performance because all the analysis is completed beforehand. For those +reasons, checking the borrowing rules at compile time is the best choice in the +majority of cases, which is why this is Rust’s default. -The advantages to checking the borrowing rules at compile time are that errors -will be caught sooner in the development process and there is no impact on -runtime performance since all the analysis is completed beforehand. For those -reasons, checking the borrowing rules at compile time is the best choice for -the majority of cases, which is why this is Rust’s default. - -The advantage to checking the borrowing rules at runtime instead is that +The advantage of checking the borrowing rules at runtime instead is that certain memory safe scenarios are then allowed, whereas they are disallowed by the compile time checks. Static analysis, like the Rust compiler, is inherently conservative. Some properties of code are impossible to detect by analyzing the -code: the most famous example is the Halting Problem, which is out of scope of -this book but an interesting topic to research if you’re interested. - - - +code: the most famous example is the Halting Problem, which is beyond the scope +of this book but is an interesting topic to research. Because some analysis is impossible, if the Rust compiler can’t be sure the -code complies with the ownership rules, it may reject a correct program; in -this way, it is conservative. If Rust were to accept an incorrect program, -users would not be able to trust in the guarantees Rust makes. However, if Rust +code complies with the ownership rules, it might reject a correct program; in +this way, it’s conservative. If Rust accepted an incorrect program, users +wouldn’t be able to trust in the guarantees Rust makes. However, if Rust rejects a correct program, the programmer will be inconvenienced, but nothing -catastrophic can occur. `RefCell` is useful when you yourself are sure that -your code follows the borrowing rules, but the compiler is not able to -understand and guarantee that. +catastrophic can occur. The `RefCell` type is useful when you’re sure your +code follows the borrowing rules, but the compiler is unable to understand and +guarantee that. -Similarly to `Rc`, `RefCell` is only for use in single-threaded scenarios -and will give you a compile time error if you try in a multithreaded context. -We’ll talk about how to get the functionality of `RefCell` in a +Similar to `Rc`, `RefCell` is only for use in single-threaded scenarios +and will give you a compile time error if you try using it in a multithreaded +context. We’ll talk about how to get the functionality of `RefCell` in a multithreaded program in Chapter 16. - - +Here is a recap of the reasons to choose `Box`, `Rc`, or `RefCell`: -To recap the reasons to choose `Box`, `Rc`, or `RefCell`: - -- `Rc` enables multiple owners of the same data; `Box` and `RefCell` +* `Rc` enables multiple owners of the same data; `Box` and `RefCell` have single owners. -- `Box` allows immutable or mutable borrows checked at compile time; `Rc` +* `Box` allows immutable or mutable borrows checked at compile time; `Rc` only allows immutable borrows checked at compile time; `RefCell` allows immutable or mutable borrows checked at runtime. -- Because `RefCell` allows mutable borrows checked at runtime, we can mutate - the value inside the `RefCell` even when the `RefCell` is itself - immutable. +* Because `RefCell` allows mutable borrows checked at runtime, we can mutate + the value inside the `RefCell` even when the `RefCell` is immutable. -The last reason is the *interior mutability* pattern. Let’s look at a case when -interior mutability is useful and discuss how this is possible. +Mutating the value inside an immutable value is the *interior mutability* +pattern. Let’s look at a situation in which interior mutability is useful and +examine how it’s possible. ### Interior Mutability: A Mutable Borrow to an Immutable Value @@ -1474,7 +1135,7 @@ fn main() { } ``` -If we try to compile this, we’ll get this error: +When we try to compile this code, we’ll get the following error: ``` error[E0596]: cannot borrow immutable local variable `x` as mutable @@ -1486,43 +1147,42 @@ error[E0596]: cannot borrow immutable local variable `x` as mutable | ^ cannot borrow mutably ``` -However, there are situations where it would be useful for a value to be able -to mutate itself in its methods, but to other code, the value would appear to -be immutable. Code outside the value’s methods would not be able to mutate the -value. `RefCell` is one way to get the ability to have interior mutability. -`RefCell` isn’t getting around the borrowing rules completely, but the -borrow checker in the compiler allows this interior mutability and the -borrowing rules are checked at runtime instead. If we violate the rules, we’ll -get a `panic!` instead of a compiler error. +However, there are situations in which it would be useful for a value to mutate +itself in its methods, but to other code, the value would appear immutable. +Code outside the value’s methods would not be able to mutate the value. Using +`RefCell` is one way to get the ability to have interior mutability. But +`RefCell` doesn’t get around the borrowing rules completely: the borrow +checker in the compiler allows this interior mutability, and the borrowing +rules are checked at runtime instead. If we violate the rules, we’ll get a +`panic!` instead of a compiler error. -Let’s work through a practical example where we can use `RefCell` to make it -possible to mutate an immutable value and see why that’s useful. +Let’s work through a practical example where we can use `RefCell` to mutate +an immutable value and see why that is useful. #### A Use Case for Interior Mutability: Mock Objects -A *test double* is the general programming concept for a type that stands in -the place of another type during testing. *Mock objects* are specific types of -test doubles that record what happens during a test so that we can assert that -the correct actions took place. +A *test double* is the general programming concept for a type used in place of +another type during testing. *Mock objects* are specific types of test doubles +that record what happens during a test so we can assert that the correct +actions took place. -While Rust doesn’t have objects in the exact same sense that other languages -have objects, and Rust doesn’t have mock object functionality built into the -standard library like some other languages do, we can definitely create a -struct that will serve the same purposes as a mock object. +Rust doesn’t have objects in the same sense as other languages have objects, +and Rust doesn’t have mock object functionality built into the standard library +like some other languages do. However, we can definitely create a struct that +will serve the same purposes as a mock object. -Here’s the scenario we’d like to test: we’re creating a library that tracks a -value against a maximum value, and sends messages based on how close to the -maximum value the current value is. This could be used for keeping track of a +Here’s the scenario we’ll test: we’ll create a library that tracks a value +against a maximum value and sends messages based on how close to the maximum +value the current value is. This library could be used for keeping track of a user’s quota for the number of API calls they’re allowed to make, for example. -Our library is only going to provide the functionality of tracking how close to -the maximum a value is, and what the messages should be at what times. -Applications that use our library will be expected to provide the actual -mechanism for sending the messages: the application could choose to put a -message in the application, send an email, send a text message, or something -else. Our library doesn’t need to know about that detail; all it needs is -something that implements a trait we’ll provide called `Messenger`. Listing -15-15 shows our library code: +Our library will only provide the functionality of tracking how close to the +maximum a value is and what the messages should be at what times. Applications +that use our library will be expected to provide the mechanism for sending the +messages: the application could put a message in the application, send an +email, send a text message, or something else. The library doesn’t need to know +that detail. All it needs is something that implements a trait we’ll provide +called `Messenger`. Listing 15-20 shows the library code: Filename: src/lib.rs @@ -1553,9 +1213,11 @@ impl<'a, T> LimitTracker<'a, T> let percentage_of_max = self.value as f64 / self.max as f64; if percentage_of_max >= 0.75 && percentage_of_max < 0.9 { - self.messenger.send("Warning: You've used up over 75% of your quota!"); + self.messenger.send("Warning: You've used up over 75% of your +quota!"); } else if percentage_of_max >= 0.9 && percentage_of_max < 1.0 { - self.messenger.send("Urgent warning: You've used up over 90% of your quota!"); + self.messenger.send("Urgent warning: You've used up over 90% of +your quota!"); } else if percentage_of_max >= 1.0 { self.messenger.send("Error: You are over your quota!"); } @@ -1563,27 +1225,27 @@ impl<'a, T> LimitTracker<'a, T> } ``` -Listing 15-15: A library to keep track of how close to a maximum value a value -is, and warn when the value is at certain levels +Listing 15-20: A library to keep track of how close to a maximum value a value +is and warn when the value is at certain levels -One important part of this code is that the `Messenger` trait has one method, -`send`, that takes an immutable reference to `self` and text of the message. -This is the interface our mock object will need to have. The other important -part is that we want to test the behavior of the `set_value` method on the -`LimitTracker`. We can change what we pass in for the `value` parameter, but -`set_value` doesn’t return anything for us to make assertions on. What we want -to be able to say is that if we create a `LimitTracker` with something that +One important part of this code is that the `Messenger` trait has one method +called `send` that takes an immutable reference to `self` and text of the +message. This is the interface our mock object needs to have. The other +important part is that we want to test the behavior of the `set_value` method +on the `LimitTracker`. We can change what we pass in for the `value` parameter, +but `set_value` doesn’t return anything for us to make assertions on. We want +to be able to say that if we create a `LimitTracker` with something that implements the `Messenger` trait and a particular value for `max`, when we pass -different numbers for `value`, the messenger gets told to send the appropriate +different numbers for `value`, the messenger is told to send the appropriate messages. -What we need is a mock object that, instead of actually sending an email or -text message when we call `send`, will only keep track of the messages it’s -told to send. We can create a new instance of the mock object, create a -`LimitTracker` that uses the mock object, call the `set_value` method on -`LimitTracker`, then check that the mock object has the messages we expect. -Listing 15-16 shows an attempt of implementing a mock object to do just that, -but that the borrow checker won’t allow: +We need a mock object that instead of sending an email or text message when we +call `send` will only keep track of the messages it’s told to send. We can +create a new instance of the mock object, create a `LimitTracker` that uses the +mock object, call the `set_value` method on `LimitTracker`, and then check that +the mock object has the messages we expect. Listing 15-21 shows an attempt of +implementing a mock object to do just that but that the borrow checker won’t +allow: Filename: src/lib.rs @@ -1620,36 +1282,36 @@ mod tests { } ``` -Listing 15-16: An attempt to implement a `MockMessenger` that isn’t allowed by +Listing 15-21: An attempt to implement a `MockMessenger` that isn’t allowed by the borrow checker This test code defines a `MockMessenger` struct that has a `sent_messages` field with a `Vec` of `String` values to keep track of the messages it’s told -to send. We also defined an associated function `new` to make it convenient to +to send. We also define an associated function `new` to make it convenient to create new `MockMessenger` values that start with an empty list of messages. We -then implement the `Messenger` trait for `MockMessenger` so that we can give a +then implement the `Messenger` trait for `MockMessenger` so we can give a `MockMessenger` to a `LimitTracker`. In the definition of the `send` method, we take the message passed in as a parameter and store it in the `MockMessenger` list of `sent_messages`. In the test, we’re testing what happens when the `LimitTracker` is told to set -`value` to something that’s over 75% of the `max` value. First, we create a new -`MockMessenger`, which will start with an empty list of messages. Then we -create a new `LimitTracker` and give it a reference to the new `MockMessenger` -and a `max` value of 100. We call the `set_value` method on the `LimitTracker` -with a value of 80, which is more than 75% of 100. Then we assert that the list -of messages that the `MockMessenger` is keeping track of should now have one -message in it. +`value` to something that is more than 75 percent of the `max` value. First, we +create a new `MockMessenger`, which will start with an empty list of messages. +Then we create a new `LimitTracker` and give it a reference to the new +`MockMessenger` and a `max` value of 100. We call the `set_value` method on the +`LimitTracker` with a value of 80, which is more than 75 percent of 100. Then +we assert that the list of messages that the `MockMessenger` is keeping track +of should now have one message in it. -There’s one problem with this test, however: +However, there’s one problem with this test, as shown here: ``` error[E0596]: cannot borrow immutable field `self.sent_messages` as mutable - --> src/lib.rs:46:13 + --> src/lib.rs:52:13 | -45 | fn send(&self, message: &str) { +51 | fn send(&self, message: &str) { | ----- use `&mut self` here to make mutable -46 | self.sent_messages.push(String::from(message)); +52 | self.sent_messages.push(String::from(message)); | ^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field ``` @@ -1659,10 +1321,10 @@ suggestion from the error text to use `&mut self` instead because then the signature of `send` wouldn’t match the signature in the `Messenger` trait definition (feel free to try and see what error message you get). -This is where interior mutability can help! We’re going to store the -`sent_messages` within a `RefCell`, and then the `send` message will be able to -modify `sent_messages` to store the messages we’ve seen. Listing 15-17 shows -what that looks like: +This is a situation in which interior mutability can help! We’ll store the +`sent_messages` within a `RefCell`, and then the `send` message will be +able to modify `sent_messages` to store the messages we’ve seen. Listing 15-22 +shows what that looks like: Filename: src/lib.rs @@ -1691,61 +1353,54 @@ mod tests { #[test] fn it_sends_an_over_75_percent_warning_message() { // --snip-- -# let mock_messenger = MockMessenger::new(); -# let mut limit_tracker = LimitTracker::new(&mock_messenger, 100); -# limit_tracker.set_value(75); assert_eq!(mock_messenger.sent_messages.borrow().len(), 1); } } ``` -Listing 15-17: Using `RefCell` to be able to mutate an inner value while the -outer value is considered immutable +Listing 15-22: Using `RefCell` to mutate an inner value while the outer +value is considered immutable The `sent_messages` field is now of type `RefCell>` instead of -`Vec`. In the `new` function, we create a new `RefCell` instance around -the empty vector. +`Vec`. In the `new` function, we create a new `RefCell>` +instance around the empty vector. For the implementation of the `send` method, the first parameter is still an immutable borrow of `self`, which matches the trait definition. We call -`borrow_mut` on the `RefCell` in `self.sent_messages` to get a mutable -reference to the value inside the `RefCell`, which is the vector. Then we can -call `push` on the mutable reference to the vector in order to keep track of -the messages seen during the test. +`borrow_mut` on the `RefCell>` in `self.sent_messages` to get a +mutable reference to the value inside the `RefCell>`, which is +the vector. Then we can call `push` on the mutable reference to the vector to +keep track of the messages sent during the test. -The last change we have to make is in the assertion: in order to see how many -items are in the inner vector, we call `borrow` on the `RefCell` to get an +The last change we have to make is in the assertion: to see how many items are +in the inner vector, we call `borrow` on the `RefCell>` to get an immutable reference to the vector. -Now that we’ve seen how to use `RefCell`, let’s dig into how it works! +Now that you’ve seen how to use `RefCell`, let’s dig into how it works! #### `RefCell` Keeps Track of Borrows at Runtime -When creating immutable and mutable references we use the `&` and `&mut` +When creating immutable and mutable references, we use the `&` and `&mut` syntax, respectively. With `RefCell`, we use the `borrow` and `borrow_mut` methods, which are part of the safe API that belongs to `RefCell`. The -`borrow` method returns the smart pointer type `Ref`, and `borrow_mut` returns -the smart pointer type `RefMut`. Both types implement `Deref` so we can treat -them like regular references. +`borrow` method returns the smart pointer type `Ref`, and `borrow_mut` +returns the smart pointer type `RefMut`. Both types implement `Deref` so +we can treat them like regular references. - - - -The `RefCell` keeps track of how many `Ref` and `RefMut` smart pointers are -currently active. Every time we call `borrow`, the `RefCell` increases its -count of how many immutable borrows are active. When a `Ref` value goes out of -scope, the count of immutable borrows goes down by one. Just like the compile -time borrowing rules, `RefCell` lets us have many immutable borrows or one -mutable borrow at any point in time. +The `RefCell` keeps track of how many `Ref` and `RefMut` smart +pointers are currently active. Every time we call `borrow`, the `RefCell` +increases its count of how many immutable borrows are active. When a `Ref` +value goes out of scope, the count of immutable borrows goes down by one. Just +like the compile time borrowing rules, `RefCell` lets us have many immutable +borrows or one mutable borrow at any point in time. If we try to violate these rules, rather than getting a compiler error like we would with references, the implementation of `RefCell` will `panic!` at -runtime. Listing 15-18 shows a modification to the implementation of `send` -from Listing 15-17 where we’re deliberately trying to create two mutable -borrows active for the same scope in order to illustrate that `RefCell` -prevents us from doing this at runtime: +runtime. Listing 15-23 shows a modification of the implementation of `send` in +Listing 15-22. We’re deliberately trying to create two mutable borrows active +for the same scope to illustrate that `RefCell` prevents us from doing this +at runtime: Filename: src/lib.rs @@ -1761,14 +1416,14 @@ impl Messenger for MockMessenger { } ``` -Listing 15-18: Creating two mutable references in the same scope to see that +Listing 15-23: Creating two mutable references in the same scope to see that `RefCell` will panic -We create a variable `one_borrow` for the `RefMut` smart pointer returned from -`borrow_mut`. Then we create another mutable borrow in the same way in the +We create a variable `one_borrow` for the `RefMut` smart pointer returned +from `borrow_mut`. Then we create another mutable borrow in the same way in the variable `two_borrow`. This makes two mutable references in the same scope, -which isn’t allowed. If we run the tests for our library, this code will -compile without any errors, but the test will fail: +which isn’t allowed. When we run the tests for our library, the code in Listing +15-23 will compile without any errors, but the test will fail: ``` ---- tests::it_sends_an_over_75_percent_warning_message stdout ---- @@ -1777,37 +1432,34 @@ compile without any errors, but the test will fail: note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -We can see that the code panicked with the message `already borrowed: +Notice that the code panicked with the message `already borrowed: BorrowMutError`. This is how `RefCell` handles violations of the borrowing rules at runtime. -Catching borrowing errors at runtime rather than compile time means that we’d -find out that we made a mistake in our code later in the development process-- -and possibly not even until our code was deployed to production. There’s also a -small runtime performance penalty our code will incur as a result of keeping -track of the borrows at runtime rather than compile time. However, using -`RefCell` made it possible for us to write a mock object that can modify itself -to keep track of the messages it has seen while we’re using it in a context -where only immutable values are allowed. We can choose to use `RefCell` -despite its tradeoffs to get more abilities than regular references give us. +Catching borrowing errors at runtime rather than compile time means that we +would find a mistake in our code later in the development process and possibly +not even until our code was deployed to production. Also, our code will incur a +small runtime performance penalty as a result of keeping track of the borrows +at runtime rather than compile time. However, using `RefCell` makes it +possible for us to write a mock object that can modify itself to keep track of +the messages it has seen while we’re using it in a context where only immutable +values are allowed. We can use `RefCell` despite its trade-offs to get more +functionality than regular references give us. ### Having Multiple Owners of Mutable Data by Combining `Rc` and `RefCell` A common way to use `RefCell` is in combination with `Rc`. Recall that `Rc` lets us have multiple owners of some data, but it only gives us immutable access to that data. If we have an `Rc` that holds a `RefCell`, -then we can get a value that can have multiple owners *and* that we can mutate! +we can get a value that can have multiple owners *and* that we can mutate! - - - -For example, recall the cons list example from Listing 15-13 where we used +For example, recall the cons list example in Listing 15-18 where we used `Rc` to let us have multiple lists share ownership of another list. Because -`Rc` only holds immutable values, we aren’t able to change any of the values -in the list once we’ve created them. Let’s add in `RefCell` to get the -ability to change the values in the lists. Listing 15-19 shows that by using a -`RefCell` in the `Cons` definition, we’re allowed to modify the value stored -in all the lists: +`Rc` only holds immutable values, we can’t change any of the values in the +list once we’ve created them. Let’s add in `RefCell` to gain the ability to +change the values in the lists. Listing 15-24 shows that by using a +`RefCell` in the `Cons` definition, we can modify the value stored in all +the lists: Filename: src/main.rs @@ -1838,30 +1490,26 @@ fn main() { } ``` -Listing 15-19: Using `Rc>` to create a `List` that we can mutate +Listing 15-24: Using `Rc>` to create a `List` that we can mutate -We create a value that’s an instance of `Rc` and store it in a +We create a value that is an instance of `Rc` and store it in a variable named `value` so we can access it directly later. Then we create a `List` in `a` with a `Cons` variant that holds `value`. We need to clone -`value` so that both `a` and `value` have ownership of the inner `5` value, -rather than transferring ownership from `value` to `a` or having `a` borrow -from `value`. +`value` so both `a` and `value` have ownership of the inner `5` value rather +than transferring ownership from `value` to `a` or having `a` borrow from +`value`. - - +We wrap the list `a` in an `Rc` so when we create lists `b` and `c`, they +can both refer to `a`, which is what we did in Listing 15-18. -We wrap the list `a` in an `Rc` so that when we create lists `b` and -`c`, they can both refer to `a`, the same as we did in Listing 15-13. - -Once we have the lists in `a`, `b`, and `c` created, we add 10 to the value in +After we’ve created the lists in `a`, `b`, and `c`, we add 10 to the value in `value`. We do this by calling `borrow_mut` on `value`, which uses the -automatic dereferencing feature we discussed in Chapter 5 (“Where’s the `->` -Operator?â€) to dereference the `Rc` to the inner `RefCell` value. The -`borrow_mut` method returns a `RefMut` smart pointer, and we use the -dereference operator on it and change the inner value. +automatic dereferencing feature we discussed in Chapter 5 (see the section +“Where’s the `->` Operator?â€) to dereference the `Rc` to the inner +`RefCell` value. The `borrow_mut` method returns a `RefMut` smart +pointer, and we use the dereference operator on it and change the inner value. -When we print out `a`, `b`, and `c`, we can see that they all have the modified +When we print `a`, `b`, and `c`, we can see that they all have the modified value of 15 rather than 5: ``` @@ -1870,36 +1518,36 @@ b after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil)) c after = Cons(RefCell { value: 10 }, Cons(RefCell { value: 15 }, Nil)) ``` -This is pretty neat! By using `RefCell`, we have an outwardly immutable -`List`, but we can use the methods on `RefCell` that provide access to its -interior mutability so we can modify our data when we need to. The runtime -checks of the borrowing rules protect us from data races, and it’s sometimes -worth trading a bit of speed for this flexibility in our data structures. +This technique is pretty neat! By using `RefCell`, we have an outwardly +immutable `List`. But we can use the methods on `RefCell` that provide +access to its interior mutability so we can modify our data when we need to. +The runtime checks of the borrowing rules protect us from data races, and it’s +sometimes worth trading a bit of speed for this flexibility in our data +structures. -The standard library has other types that provide interior mutability, too, -like `Cell`, which is similar except that instead of giving references to -the inner value, the value is copied in and out of the `Cell`. There’s also -`Mutex`, which offers interior mutability that’s safe to use across threads, -and we’ll be discussing its use in the next chapter on concurrency. Check out -the standard library docs for more details on the differences between these -types. +The standard library has other types that provide interior mutability, such as +`Cell`, which is similar except that instead of giving references to the +inner value, the value is copied in and out of the `Cell`. There’s also +`Mutex`, which offers interior mutability that’s safe to use across threads; +we’ll discuss its use in Chapter 16. Check out the standard library docs for +more details on the differences between these types. ## Reference Cycles Can Leak Memory -Rust’s memory safety guarantees make it *difficult* to accidentally create -memory that’s never cleaned up, known as a *memory leak*, but not impossible. -Entirely preventing memory leaks is not one of Rust’s guarantees in the same +Rust’s memory safety guarantees make it *difficult* but not impossible to +accidentally create memory that is never cleaned up (known as a *memory leak*). +Preventing memory leaks entirely is not one of Rust’s guarantees in the same way that disallowing data races at compile time is, meaning memory leaks are -memory safe in Rust. We can see this with `Rc` and `RefCell`: it’s -possible to create references where items refer to each other in a cycle. This -creates memory leaks because the reference count of each item in the cycle will -never reach 0, and the values will never be dropped. +memory safe in Rust. We can see that Rust allows memory leaks by using `Rc` +and `RefCell`: it’s possible to create references where items refer to each +other in a cycle. This creates memory leaks because the reference count of each +item in the cycle will never reach 0, and the values will never be dropped. ### Creating a Reference Cycle -Let’s take a look at how a reference cycle might happen and how to prevent it, +Let’s look at how a reference cycle might happen and how to prevent it, starting with the definition of the `List` enum and a `tail` method in Listing -15-20: +15-25: Filename: src/main.rs @@ -1924,57 +1572,25 @@ impl List { } ``` -Listing 15-20: A cons list definition that holds a `RefCell` so that we can +Listing 15-25: A cons list definition that holds a `RefCell` so we can modify what a `Cons` variant is referring to -We’re using another variation of the `List` definition from Listing 15-6. The +We’re using another variation of the `List` definition in Listing 15-5. The second element in the `Cons` variant is now `RefCell>`, meaning that instead of having the ability to modify the `i32` value like we did in Listing -15-19, we want to be able to modify which `List` a `Cons` variant is pointing -to. We’ve also added a `tail` method to make it convenient for us to access the -second item, if we have a `Cons` variant. +15-24, we want to modify which `List` a `Cons` variant is pointing to. We’re +also adding a `tail` method to make it convenient for us to access the second +item if we have a `Cons` variant. - - - -In listing 15-21, we’re adding a `main` function that uses the definitions from -Listing 15-20. This code creates a list in `a`, a list in `b` that points to +In Listing 15-26, we’re adding a `main` function that uses the definitions in +Listing 15-25. This code creates a list in `a` and a list in `b` that points to the list in `a`, and then modifies the list in `a` to point to `b`, which creates a reference cycle. There are `println!` statements along the way to -show what the reference counts are at various points in this process. - - - +show what the reference counts are at various points in this process: Filename: src/main.rs ``` -# use List::{Cons, Nil}; -# use std::rc::Rc; -# use std::cell::RefCell; -# #[derive(Debug)] -# enum List { -# Cons(i32, RefCell>), -# Nil, -# } -# -# impl List { -# fn tail(&self) -> Option<&RefCell>> { -# match *self { -# Cons(_, ref item) => Some(item), -# Nil => None, -# } -# } -# } -# fn main() { let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil)))); @@ -1987,7 +1603,7 @@ fn main() { println!("b initial rc count = {}", Rc::strong_count(&b)); println!("b next item = {:?}", b.tail()); - if let Some(ref link) = a.tail() { + if let Some(link) = a.tail() { *link.borrow_mut() = Rc::clone(&b); } @@ -2000,22 +1616,22 @@ fn main() { } ``` -Listing 15-21: Creating a reference cycle of two `List` values pointing to each +Listing 15-26: Creating a reference cycle of two `List` values pointing to each other -We create an `Rc` instance holding a `List` value in the variable `a` with an -initial list of `5, Nil`. We then create an `Rc` instance holding another -`List` value in the variable `b` that contains the value 10, then points to the -list in `a`. +We create an `Rc` instance holding a `List` value in the variable `a` +with an initial list of `5, Nil`. We then create an `Rc` instance +holding another `List` value in the variable `b` that contains the value 10 and +then points to the list in `a`. -Finally, we modify `a` so that it points to `b` instead of `Nil`, which creates -a cycle. We do that by using the `tail` method to get a reference to the -`RefCell` in `a`, which we put in the variable `link`. Then we use the -`borrow_mut` method on the `RefCell` to change the value inside from an `Rc` -that holds a `Nil` value to the `Rc` in `b`. +We modify `a` so it points to `b` instead of `Nil`, which creates a cycle. We +do that by using the `tail` method to get a reference to the +`RefCell>` in `a`, which we put in the variable `link`. Then we use +the `borrow_mut` method on the `RefCell>` to change the value inside +from an `Rc` that holds a `Nil` value to the `Rc` in `b`. -If we run this code, keeping the last `println!` commented out for the moment, -we’ll get this output: +When we run this code, keeping the last `println!` commented out for the +moment, we’ll get this output: ``` a initial rc count = 1 @@ -2027,117 +1643,75 @@ b rc count after changing a = 2 a rc count after changing a = 2 ``` -We can see that the reference count of the `Rc` instances in both `a` and `b` -are 2 after we change the list in `a` to point to `b`. At the end of `main`, -Rust will try and drop `b` first, which will decrease the count in each of the -`Rc` instances in `a` and `b` by one. +The reference count of the `Rc` instances in both `a` and `b` are 2 +after we change the list in `a` to point to `b`. At the end of `main`, Rust +will try to drop `b` first, which will decrease the count in each of the +`Rc` instances in `a` and `b` by one. - - - - - - -However, because `a` is still referencing the `Rc` that was in `b`, that `Rc` -has a count of 1 rather than 0, so the memory the `Rc` has on the heap won’t be -dropped. The memory will just sit there with a count of one, forever. - -To visualize this, we’ve created a reference cycle that looks like Figure 15-22: +However, because `a` is still referencing the `Rc` that was in `b`, +that `Rc` has a count of 1 rather than 0, so the memory the +`Rc` has on the heap won’t be dropped. The memory will just sit there +with a count of one, forever. To visualize this reference cycle, we’ve created +a diagram in Figure 15-4: Reference cycle of lists -Figure 15-22: A reference cycle of lists `a` and `b` pointing to each other +Figure 15-4: A reference cycle of lists `a` and `b` pointing to each other -If you uncomment the last `println!` and run the program, Rust will try and -print this cycle out with `a` pointing to `b` pointing to `a` and so forth -until it overflows the stack. +If you uncomment the last `println!` and run the program, Rust will try to +print this cycle with `a` pointing to `b` pointing to `a` and so forth until it +overflows the stack. - - - -In this specific case, right after we create the reference cycle, the program -ends. The consequences of this cycle aren’t so dire. If a more complex program +In this case, right after we create the reference cycle, the program ends. The +consequences of this cycle aren’t very dire. If a more complex program allocates lots of memory in a cycle and holds onto it for a long time, the -program would be using more memory than it needs, and might overwhelm the -system and cause it to run out of available memory. +program would use more memory than it needs and might overwhelm the system, +causing it to run out of available memory. Creating reference cycles is not easily done, but it’s not impossible either. If you have `RefCell` values that contain `Rc` values or similar nested -combinations of types with interior mutability and reference counting, be aware -that you have to ensure you don’t create cycles yourself; you can’t rely on -Rust to catch them. Creating a reference cycle would be a logic bug in your -program that you should use automated tests, code reviews, and other software -development practices to minimize. +combinations of types with interior mutability and reference counting, you must +ensure that you don’t create cycles; you can’t rely on Rust to catch them. +Creating a reference cycle would be a logic bug in your program that you should +use automated tests, code reviews, and other software development practices to +minimize. - - - -Another solution is reorganizing your data structures so that some references -express ownership and some references don’t. In this way, we can have cycles -made up of some ownership relationships and some non-ownership relationships, -and only the ownership relationships affect whether a value may be dropped or -not. In Listing 15-20, we always want `Cons` variants to own their list, so -reorganizing the data structure isn’t possible. Let’s look at an example using -graphs made up of parent nodes and child nodes to see when non-ownership -relationships are an appropriate way to prevent reference cycles. +Another solution for avoiding reference cycles is reorganizing your data +structures so that some references express ownership and some references don’t. +As a result, you can have cycles made up of some ownership relationships and +some non-ownership relationships, and only the ownership relationships affect +whether or not a value can be dropped. In Listing 15-25, we always want `Cons` +variants to own their list, so reorganizing the data structure isn’t possible. +Let’s look at an example using graphs made up of parent nodes and child nodes +to see when non-ownership relationships are an appropriate way to prevent +reference cycles. ### Preventing Reference Cycles: Turn an `Rc` into a `Weak` -So far, we’ve shown how calling `Rc::clone` increases the `strong_count` of an -`Rc` instance, and that an `Rc` instance is only cleaned up if its -`strong_count` is 0. We can also create a *weak reference* to the value within -an `Rc` instance by calling `Rc::downgrade` and passing a reference to the -`Rc`. When we call `Rc::downgrade`, we get a smart pointer of type `Weak`. -Instead of increasing the `strong_count` in the `Rc` instance by one, calling -`Rc::downgrade` increases the `weak_count` by one. The `Rc` type uses -`weak_count` to keep track of how many `Weak` references exist, similarly to -`strong_count`. The difference is the `weak_count` does not need to be 0 in -order for the `Rc` instance to be cleaned up. +So far, we’ve demonstrated that calling `Rc::clone` increases the +`strong_count` of an `Rc` instance, and an `Rc` instance is only +cleaned up if its `strong_count` is 0. We can also create a *weak reference* to +the value within an `Rc` instance by calling `Rc::downgrade` and passing a +reference to the `Rc`. When we call `Rc::downgrade`, we get a smart +pointer of type `Weak`. Instead of increasing the `strong_count` in the +`Rc` instance by one, calling `Rc::downgrade` increases the `weak_count` +by one. The `Rc` type uses `weak_count` to keep track of how many +`Weak` references exist, similar to `strong_count`. The difference is the +`weak_count` doesn’t need to be 0 for the `Rc` instance to be cleaned up. - - - -Strong references are how we can share ownership of an `Rc` instance. Weak +Strong references are how we can share ownership of an `Rc` instance. Weak references don’t express an ownership relationship. They won’t cause a -reference cycle since any cycle involving some weak references will be broken +reference cycle because any cycle involving some weak references will be broken once the strong reference count of values involved is 0. - - - -Because the value that `Weak` references might have been dropped, in order -to do anything with the value that a `Weak` is pointing to, we have to check -to make sure the value is still around. We do this by calling the `upgrade` -method on a `Weak` instance, which will return an `Option>`. We’ll get -a result of `Some` if the `Rc` value has not been dropped yet, and `None` if -the `Rc` value has been dropped. Because `upgrade` returns an `Option`, we can -be sure that Rust will handle both the `Some` case and the `None` case, and -there won’t be an invalid pointer. +Because the value that `Weak` references might have been dropped, to do +anything with the value that a `Weak` is pointing to, we must make sure the +value still exists. We do this by calling the `upgrade` method on a `Weak` +instance, which will return an `Option>`. We’ll get a result of `Some` if +the `Rc` value has not been dropped yet and a result of `None` if the +`Rc` value has been dropped. Because `upgrade` returns an `Option`, Rust +will ensure that we handle the `Some` case and the `None` case, and there won’t +be an invalid pointer. As an example, rather than using a list whose items know only about the next item, we’ll create a tree whose items know about their children items *and* @@ -2145,8 +1719,9 @@ their parent items. #### Creating a Tree Data Structure: a `Node` with Child Nodes -To start building this tree, we’ll create a struct named `Node` that holds its -own `i32` value as well as references to its children `Node` values: +To start, we’ll build a tree with nodes that know about their child nodes. +We’ll create a struct named `Node` that holds its own `i32` value as well as +references to its children `Node` values: Filename: src/main.rs @@ -2161,28 +1736,19 @@ struct Node { } ``` -We want a `Node` to own its children, and we want to be able to share that -ownership with variables so we can access each `Node` in the tree directly. To -do this, we define the `Vec` items to be values of type `Rc`. We also -want to be able to modify which nodes are children of another node, so we have -a `RefCell` in `children` around the `Vec`. +We want a `Node` to own its children, and we want to share that ownership with +variables so we can access each `Node` in the tree directly. To do this, we +define the `Vec` items to be values of type `Rc`. We also want to +modify which nodes are children of another node, so we have a `RefCell` in +`children` around the `Vec>`. -Next, let’s use our struct definition and create one `Node` instance named +Next, we’ll use our struct definition and create one `Node` instance named `leaf` with the value 3 and no children, and another instance named `branch` -with the value 5 and `leaf` as one of its children, as shown in Listing 15-23: +with the value 5 and `leaf` as one of its children, as shown in Listing 15-27: Filename: src/main.rs ``` -# use std::rc::Rc; -# use std::cell::RefCell; -# -# #[derive(Debug)] -# struct Node { -# value: i32, -# children: RefCell>>, -# } -# fn main() { let leaf = Rc::new(Node { value: 3, @@ -2196,36 +1762,33 @@ fn main() { } ``` -Listing 15-23: Creating a `leaf` node with no children and a `branch` node with +Listing 15-27: Creating a `leaf` node with no children and a `branch` node with `leaf` as one of its children -We clone the `Rc` in `leaf` and store that in `branch`, meaning the `Node` in -`leaf` now has two owners: `leaf` and `branch`. We can get from `branch` to -`leaf` through `branch.children`, but there’s no way to get from `leaf` to -`branch`. `leaf` has no reference to `branch` and doesn’t know they are -related. We’d like `leaf` to know that `branch` is its parent. +We clone the `Rc` in `leaf` and store that in `branch`, meaning the +`Node` in `leaf` now has two owners: `leaf` and `branch`. We can get from +`branch` to `leaf` through `branch.children`, but there’s no way to get from +`leaf` to `branch`. The reason is that `leaf` has no reference to `branch` and +doesn’t know they’re related. We want `leaf` to know that `branch` is its +parent. We’ll do that next. -#### Adding a Reference from a Child to its Parent +#### Adding a Reference from a Child to Its Parent To make the child node aware of its parent, we need to add a `parent` field to our `Node` struct definition. The trouble is in deciding what the type of `parent` should be. We know it can’t contain an `Rc` because that would -create a reference cycle, with `leaf.parent` pointing to `branch` and +create a reference cycle with `leaf.parent` pointing to `branch` and `branch.children` pointing to `leaf`, which would cause their `strong_count` -values to never be zero. +values to never be 0. Thinking about the relationships another way, a parent node should own its children: if a parent node is dropped, its child nodes should be dropped as well. However, a child should not own its parent: if we drop a child node, the parent should still exist. This is a case for weak references! -So instead of `Rc`, we’ll make the type of `parent` use `Weak`, specifically -a `RefCell>`. Now our `Node` struct definition looks like this: - - - +So instead of `Rc`, we’ll make the type of `parent` use `Weak`, +specifically a `RefCell>`. Now our `Node` struct definition looks +like this: Filename: src/main.rs @@ -2241,35 +1804,13 @@ struct Node { } ``` - - - -This way, a node will be able to refer to its parent node, but does not own its -parent. In Listing 15-24, let’s update `main` to use this new definition so -that the `leaf` node will have a way to refer to its parent, `branch`: - - - +Now a node will be able to refer to its parent node but doesn’t own its parent. +In Listing 15-28, we update `main` to use this new definition so the `leaf` +node will have a way to refer to its parent, `branch`: Filename: src/main.rs ``` -# use std::rc::{Rc, Weak}; -# use std::cell::RefCell; -# -# #[derive(Debug)] -# struct Node { -# value: i32, -# parent: RefCell>, -# children: RefCell>>, -# } -# fn main() { let leaf = Rc::new(Node { value: 3, @@ -2291,45 +1832,33 @@ fn main() { } ``` -Listing 15-24: A `leaf` node with a `Weak` reference to its parent node, -`branch` - - +Listing 15-28: A `leaf` node with a `Weak` reference to its parent node `branch` Creating the `leaf` node looks similar to how creating the `leaf` node looked -in Listing 15-23, with the exception of the `parent` field: `leaf` starts out -without a parent, so we create a new, empty `Weak` reference instance. +in Listing 15-27 with the exception of the `parent` field: `leaf` starts out +without a parent, so we create a new, empty `Weak` reference instance. At this point, when we try to get a reference to the parent of `leaf` by using the `upgrade` method, we get a `None` value. We see this in the output from the -first `println!`: +first `println!` statement: ``` leaf parent = None ``` - - +When we create the `branch` node, it will also have a new `Weak` +reference in the `parent` field, because `branch` doesn’t have a parent node. +We still have `leaf` as one of the children of `branch`. Once we have the +`Node` instance in `branch`, we can modify `leaf` to give it a `Weak` +reference to its parent. We use the `borrow_mut` method on the +`RefCell>` in the `parent` field of `leaf`, and then we use the +`Rc::downgrade` function to create a `Weak` reference to `branch` from +the `Rc` in `branch.` -When we create the `branch` node, it will also have a new `Weak` reference, -since `branch` does not have a parent node. We still have `leaf` as one of the -children of `branch`. Once we have the `Node` instance in `branch`, we can -modify `leaf` to give it a `Weak` reference to its parent. We use the -`borrow_mut` method on the `RefCell` in the `parent` field of `leaf`, then we -use the `Rc::downgrade` function to create a `Weak` reference to `branch` from -the `Rc` in `branch.` - - - - -When we print out the parent of `leaf` again, this time we’ll get a `Some` -variant holding `branch`: `leaf` can now access its parent! When we print out -`leaf`, we also avoid the cycle that eventually ended in a stack overflow like -we had in Listing 15-21: the `Weak` references are printed as `(Weak)`: +When we print the parent of `leaf` again, this time we’ll get a `Some` variant +holding `branch`: now `leaf` can access its parent! When we print `leaf`, we +also avoid the cycle that eventually ended in a stack overflow like we had in +Listing 15-26: the `Weak` references are printed as `(Weak)`: ``` leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) }, @@ -2343,11 +1872,11 @@ cycle. We can also tell this by looking at the values we get from calling #### Visualizing Changes to `strong_count` and `weak_count` -Let’s look at how the `strong_count` and `weak_count` values of the `Rc` +Let’s look at how the `strong_count` and `weak_count` values of the `Rc` instances change by creating a new inner scope and moving the creation of -`branch` into that scope. This will let us see what happens when `branch` is +`branch` into that scope. By doing so, we can see what happens when `branch` is created and then dropped when it goes out of scope. The modifications are shown -in Listing 15-25: +in Listing 15-29: Filename: src/main.rs @@ -2371,6 +1900,7 @@ fn main() { parent: RefCell::new(Weak::new()), children: RefCell::new(vec![Rc::clone(&leaf)]), }); + *leaf.parent.borrow_mut() = Rc::downgrade(&branch); println!( @@ -2395,60 +1925,53 @@ fn main() { } ``` -Listing 15-25: Creating `branch` in an inner scope and examining strong and +Listing 15-29: Creating `branch` in an inner scope and examining strong and weak reference counts -Once `leaf` is created, its `Rc` has a strong count of 1 and a weak count of 0. -In the inner scope we create `branch` and associate it with `leaf`, at which -point the `Rc` in `branch` will have a strong count of 1 and a weak count of 1 -(for `leaf.parent` pointing to `branch` with a `Weak`). Here `leaf` will -have a strong count of 2, because `branch` now has a clone of the `Rc` of -`leaf` stored in `branch.children`, but will still have a weak count of 0. +After `leaf` is created, its `Rc` has a strong count of 1 and a weak +count of 0. In the inner scope, we create `branch` and associate it with +`leaf`, at which point when we print the counts, the `Rc` in `branch` +will have a strong count of 1 and a weak count of 1 (for `leaf.parent` pointing +to `branch` with a `Weak`). When we print the counts in `leaf`, we’ll see +it will have a strong count of 2, because `branch` now has a clone of the +`Rc` of `leaf` stored in `branch.children` but will still have a weak +count of 0. When the inner scope ends, `branch` goes out of scope and the strong count of -the `Rc` decreases to 0, so its `Node` gets dropped. The weak count of 1 from -`leaf.parent` has no bearing on whether `Node` is dropped or not, so we don’t -get any memory leaks! +the `Rc` decreases to 0, so its `Node` is dropped. The weak count of 1 +from `leaf.parent` has no bearing on whether or not `Node` is dropped, so we +don’t get any memory leaks! If we try to access the parent of `leaf` after the end of the scope, we’ll get -`None` again. At the end of the program, the `Rc` in `leaf` has a strong count -of 1 and a weak count of 0, because the variable `leaf` is now the only -reference to the `Rc` again. +`None` again. At the end of the program, the `Rc` in `leaf` has a strong +count of 1 and a weak count of 0, because the variable `leaf` is now the only +reference to the `Rc` again. - - - -All of the logic that manages the counts and value dropping is built in to -`Rc` and `Weak` and their implementations of the `Drop` trait. By specifying -that the relationship from a child to its parent should be a `Weak` -reference in the definition of `Node`, we’re able to have parent nodes point to -child nodes and vice versa without creating a reference cycle and memory leaks. - - - +All of the logic that manages the counts and value dropping is built into +`Rc` and `Weak` and their implementations of the `Drop` trait. By +specifying that the relationship from a child to its parent should be a +`Weak` reference in the definition of `Node`, we’re able to have parent +nodes point to child nodes and vice versa without creating a reference cycle +and memory leaks. ## Summary -This chapter covered how you can use smart pointers to make different -guarantees and tradeoffs than those Rust makes by default with regular -references. `Box` has a known size and points to data allocated on the heap. -`Rc` keeps track of the number of references to data on the heap so that -data can have multiple owners. `RefCell` with its interior mutability gives -us a type that can be used when we need an immutable type but need the ability -to change an inner value of that type, and enforces the borrowing rules at -runtime instead of at compile time. +This chapter covered how to use smart pointers to make different guarantees and +trade-offs than those Rust makes by default with regular references. The +`Box` type has a known size and points to data allocated on the heap. The +`Rc` type keeps track of the number of references to data on the heap, so +that data can have multiple owners. The `RefCell` type with its interior +mutability gives us a type that we can use when we need an immutable type but +need to change an inner value of that type; it also enforces the borrowing +rules at runtime instead of at compile time. -We also discussed the `Deref` and `Drop` traits that enable a lot of the +Also discussed were the `Deref` and `Drop` traits that enable a lot of the functionality of smart pointers. We explored reference cycles that can cause -memory leaks, and how to prevent them using `Weak`. +memory leaks and how to prevent them using `Weak`. If this chapter has piqued your interest and you want to implement your own -smart pointers, check out “The Nomicon†at -*https://doc.rust-lang.org/stable/nomicon/* for even more useful information. +smart pointers, check out “The Rustonomicon†at +*https://doc.rust-lang.org/stable/nomicon/* for more useful information. -Next, let’s talk about concurrency in Rust. We’ll even learn about a few new +Next, we’ll talk about concurrency in Rust. You’ll even learn about a few new smart pointers. diff --git a/src/doc/book/second-edition/nostarch/chapter16.md b/src/doc/book/second-edition/nostarch/chapter16.md index a1c18f896f..a605b19902 100644 --- a/src/doc/book/second-edition/nostarch/chapter16.md +++ b/src/doc/book/second-edition/nostarch/chapter16.md @@ -6,129 +6,101 @@ Handling concurrent programming safely and efficiently is another of Rust’s major goals. *Concurrent programming*, where different parts of a program execute independently, and *parallel programming*, where different parts of a -program are executing at the same time, are becoming increasingly important as -more computers have multiple processors to take advantage of. Historically, +program execute at the same time, are becoming increasingly important as more +computers take advantage of their multiple processors. Historically, programming in these contexts has been difficult and error prone: Rust hopes to change that. Initially, the Rust team thought that ensuring memory safety and preventing concurrency problems were two separate challenges to be solved with different -methods. Over time, they discovered that the ownership and type systems are a -powerful set of tools to help in dealing with both memory safety *and* -concurrency problems! By leveraging ownership and type checking, many -concurrency errors are *compile time* errors in Rust, rather than runtime -errors. Rather than spending lots of time trying to reproduce the exact -circumstances under which a runtime concurrency bug occurs, incorrect code will -refuse to compile with an error explaining the problem. This lets you fix your -code while you’re working on it, rather than potentially after it’s been -shipped to production. We’ve nicknamed this aspect of Rust *fearless -concurrency*. Fearless concurrency allows you to write code that’s free of +methods. Over time, the team discovered that the ownership and type systems are +a powerful set of tools to help manage memory safety *and* concurrency +problems! By leveraging ownership and type checking, many concurrency errors +are *compile time* errors in Rust rather than runtime errors. Therefore, rather +than you spending lots of time trying to reproduce the exact circumstances +under which a runtime concurrency bug occurs, incorrect code will refuse to +compile and present an error explaining the problem. As a result, you can fix +your code while you’re working on it rather than potentially after it has been +shipped to production. We’ve nicknamed this aspect of Rust *fearless* +*concurrency*. Fearless concurrency allows you to write code that is free of 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 +> concurrent and/or parallel whenever we use concurrent. -> Note: we’ll be referring to many of the problems here as *concurrent* rather -> than being more precise by saying *concurrent and/or parallel*, for -> simplicity’s sake. If this were a book specifically about concurrency and/or -> parallelism, we’d be sure to be more specific. For this chapter, please -> mentally substitute *concurrent and/or parallel* whenever we say *concurrent*. +Many languages are dogmatic about the solutions they offer for handling +concurrent problems. For example, Erlang has elegant functionality for message +passing concurrency but has only obscure ways to share state between threads. +Supporting only a subset of possible solutions is a reasonable strategy for +higher-level languages, because a higher-level language promises benefits from +giving up some control to gain abstractions. However, lower-level languages are +expected to provide the solution with the best performance in any given +situation and have fewer abstractions over the hardware. Therefore, Rust offers +a variety of tools for modeling problems in whatever way is appropriate for +your situation and requirements. - - - -Many languages are strongly opinionated about the solutions they offer for -dealing with concurrent problems. For example, Erlang has elegant functionality -for message passing concurrency, but only obscure ways to share state between -threads. Only supporting a subset of possible solutions is a reasonable -strategy for higher-level languages to take, because a higher-level language -promises benefits from giving up some control in order to gain abstractions. -However, lower-level languages are expected to provide the solution with the -best performance in any given situation, and have fewer abstractions over the -hardware. Rust, therefore, gives us a variety of tools for modeling your -problems in whatever way is appropriate for your situation and requirements. - -Here’s what we’ll cover in this chapter: +Here are the topics we’ll cover in this chapter: * How to create threads to run multiple pieces of code at the same time -* *Message passing* concurrency, where channels are used to send messages - between threads. +* *Message passing* concurrency, where channels send messages between threads * *Shared state* concurrency, where multiple threads have access to some piece - of data. + of data * The `Sync` and `Send` traits, which extend Rust’s concurrency guarantees to - user-defined types as well as types provided by the standard library. + user-defined types as well as types provided by the standard library ## Using Threads to Run Code Simultaneously -In most operating systems today, an executed program’s code is run in a -*process*, and the operating system manages multiple process at once. Within +In most current operating systems, an executed program’s code is run in a +*process*, and the operating system manages multiple processes at once. Within your program, you can also have independent parts that run simultaneously. The feature that runs these independent parts is called *threads*. - - - -Splitting the computation in your program up into multiple threads can improve -performance, since the program will be doing multiple things at the same time, -but it also adds complexity. Because threads may run simultaneously, there’s no +Splitting the computation in your program into multiple threads can improve +performance because the program does multiple tasks at the same time, but it +also adds complexity. Because threads can run simultaneously, there’s no inherent guarantee about the order in which parts of your code on different -threads will run. This can lead to problems such as: +threads will run. This can lead to problems, such as: -- Race conditions, where threads are accessing data or resources in an +* Race conditions, where threads are accessing data or resources in an inconsistent order -- Deadlocks, where two threads are waiting for each other to finish using a - resource the other thread has, which prevents both threads from continuing -- Bugs that only happen in certain situations and are hard to reproduce and - fix reliably +* Deadlocks, where two threads are waiting for each other to finish using a + resource the other thread has, preventing both threads from continuing +* Bugs that only happen in certain situations and are hard to reproduce and fix + reliably - - - -Rust attempts to mitigate negative effects of using threads. Programming in a -multithreaded context still takes careful thought and requires a code structure -that’s different from programs that run in a single thread. +Rust attempts to mitigate the negative effects of using threads. Programming in +a multithreaded context still takes careful thought and requires a code +structure that is different from programs that run in a single thread. Programming languages implement threads in a few different ways. Many operating systems provide an API for creating new threads. This model where a language calls the operating system APIs to create threads is sometimes called *1:1*, -one OS thread per one language thread. +one operating system thread per one language thread. Many programming languages provide their own special implementation of threads. Programming language-provided threads are known as *green* threads, and languages that use these green threads will execute them in the context of a different number of operating system threads. For this reason, the green -threaded model is called the *M:N* model, `M` green threads per `N` OS threads, -where `M` and `N` are not necessarily the same number. +threaded model is called the *M:N* model: `M` green threads per `N` operating +system threads, where `M` and `N` are not necessarily the same number. -Each model has its own advantages and tradeoffs, and the tradeoff most -important to Rust is runtime support. *Runtime* is a confusing term and can -have different meanings in different contexts. +Each model has its own advantages and trade-offs, and the trade-off most +important to Rust is runtime support. Runtime is a confusing term and can have +different meanings in different contexts. - - - -In this context, by runtime we mean code that’s included by the language in +In this context, by *runtime* we mean code that is included by the language in every binary. This code can be large or small depending on the language, but every non-assembly language will have some amount of runtime code. For that -reason, colloquially when people say a language has “no runtime†they often +reason, colloquially when people say a language has “no runtime,†they often mean “small runtime.†Smaller runtimes have fewer features but have the advantage of resulting in smaller binaries, which make it easier to combine the -language with other languages in more contexts. While many languages are okay -with increasing the runtime size in exchange for more features, Rust needs to -have nearly no runtime, and cannot compromise on being able to call into C in -order to maintain performance. +language with other languages in more contexts. Although many languages are +okay with increasing the runtime size in exchange for more features, Rust needs +to have nearly no runtime and cannot compromise on being able to call into C to +maintain performance. The green threading M:N model requires a larger language runtime to manage threads. As such, the Rust standard library only provides an implementation of @@ -142,7 +114,7 @@ thread-related API provided by the standard library. ### Creating a New Thread with `spawn` -To create a new thread, we call the `thread::spawn` function, and pass it a +To create a new thread, we call the `thread::spawn` function and pass it a closure (we talked about closures in Chapter 13) containing the code we want to run in the new thread. The example in Listing 16-1 prints some text from a main thread and other text from a new thread: @@ -151,16 +123,19 @@ Filename: src/main.rs ``` use std::thread; +use std::time::Duration; fn main() { thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); + thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!("hi number {} from the main thread!", i); + thread::sleep(Duration::from_millis(1)); } } ``` @@ -169,9 +144,9 @@ Listing 16-1: Creating a new thread to print one thing while the main thread prints something else Note that with this function, the new thread will be stopped when the main -thread ends, whether it has finished running or not. The output from this -program might be a little different every time, but it will look similar to -this: +thread ends, whether or not it has finished running. The output from this +program might be a little different every time, but it will look similar to the +following: ``` hi number 1 from the main thread! @@ -185,60 +160,53 @@ hi number 4 from the spawned thread! hi number 5 from the spawned thread! ``` - - +The calls to `thread::sleep` force a thread to stop its execution for a short +duration, which allows a different thread to run. The threads will probably +take turns, but that isn’t guaranteed: it depends on how your operating system +schedules the threads. In this run, the main thread printed first, even though +the print statement from the spawned thread appears first in the code. And even +though we told the spawned thread to print until `i` is 9, it only got to 5 +before the main thread shut down. -The threads will probably take turns, but that’s not guaranteed: it depends on -how your operating system schedules the threads. In this run, the main thread -printed first, even though the print statement from the spawned thread appears -first in the code. And even though we told the spawned thread to print until -`i` is 9, it only got to 5 before the main thread shut down. +If you run this code and only see output from the main thread, or don’t see any +overlap, try increasing the numbers in the ranges to create more opportunities +for the operating system to switch between the threads. -If you run this code and only see one thread, or don’t see any overlap, try -increasing the numbers in the ranges to create more opportunities for a thread -to take a break and give the other thread a turn. - -#### Waiting for All Threads to Finish Using `join` Handles +### 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, because the main thread ends before the spawned thread is done, -there’s actually no guarantee that the spawned thread will get to run at all, -because there’s no guarantee on the order in which threads run! +the time due to the main thread ending, but there is no 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! - - - -We can fix this by saving the return value of `thread::spawn` in a variable. +We can fix the problem of the spawned thread not getting to run, or not getting +to run completely, by saving the return value of `thread::spawn` in a variable. The return type of `thread::spawn` is `JoinHandle`. A `JoinHandle` is an owned value that, when we call the `join` method on it, will wait for its thread to finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created -in Listing 16-1 and call `join` in order to make sure the spawned thread -finishes before the `main` exits: - - - +in Listing 16-1 and call `join` to make sure the spawned thread finishes before +`main` exits: Filename: src/main.rs ``` use std::thread; +use std::time::Duration; fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); + thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!("hi number {} from the main thread!", i); + thread::sleep(Duration::from_millis(1)); } - handle.join(); + handle.join().unwrap(); } ``` @@ -248,12 +216,8 @@ thread is run to completion Calling `join` on the handle blocks the thread currently running until the thread represented by the handle terminates. *Blocking* a thread means that thread is prevented from performing work or exiting. Because we’ve put the call -to `join` after the main thread’s `for` loop, running this example should -produce output that looks something like this: - - +to `join` after the main thread’s `for` loop, running Listing 16-2 should +produce output similar to this: ``` hi number 1 from the main thread! @@ -271,33 +235,37 @@ hi number 8 from the spawned thread! hi number 9 from the spawned thread! ``` -The two threads are still alternating, but the main thread waits because of the +The two threads continue alternating, but the main thread waits because of the call to `handle.join()` and does not end until the spawned thread is finished. -If we instead move `handle.join()` before the `for` loop in main, like this: +But let’s see what happens when we instead move `handle.join()` before the +`for` loop in `main`, like this: Filename: src/main.rs ``` use std::thread; +use std::time::Duration; fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); + thread::sleep(Duration::from_millis(1)); } }); - handle.join(); + handle.join().unwrap(); for i in 1..5 { println!("hi number {} from the main thread!", i); + thread::sleep(Duration::from_millis(1)); } } ``` The main thread will wait for the spawned thread to finish and then run its -`for` loop, so the output won’t be interleaved anymore: +`for` loop, so the output won’t be interleaved anymore, as shown here: ``` hi number 1 from the spawned thread! @@ -315,29 +283,29 @@ hi number 3 from the main thread! hi number 4 from the main thread! ``` -Thinking about a small thing such as where to call `join` can affect whether -your threads are actually running at the same time or not. +Thinking about such a small detail as where to call `join` can affect whether +or not your threads run at the same time. ### Using `move` Closures with Threads -The `move` closure, which we didn’t cover in Chapter 13, is often used -alongside `thread::spawn`, as it allows us to use data from one thread in +The `move` closure, which we mentioned briefly in Chapter 13, is often used +alongside `thread::spawn` because it allows us to use data from one thread in another thread. -In Chapter 13, we said that “Creating closures that capture values from their -environment is mostly used in the context of starting new threads.†+In Chapter 13, we said that “If we want to force the closure to take ownership +of the values it uses in the environment, we can use the `move` keyword before +the parameter list. This technique is mostly useful when passing a closure to a +new thread to move the data so it’s owned by the new thread.†- - -Now we’re creating new threads, so let’s talk about capturing values in -closures! +Now that we’re creating new threads, we’ll talk about capturing values in +closures. Notice in Listing 16-1 that the closure we pass to `thread::spawn` takes no arguments: we’re not using any data from the main thread in the spawned -thread’s code. In order to do so, the spawned thread’s closure must capture the -values it needs. Listing 16-3 shows an attempt to create a vector in the main -thread and use it in the spawned thread. However, this won’t yet work, as -you’ll see in a moment: +thread’s code. To do so, the spawned thread’s closure must capture the values +it needs. Listing 16-3 shows an attempt to create a vector in the main thread +and use it in the spawned thread. However, this won’t yet work, as you’ll see +in a moment: Filename: src/main.rs @@ -351,23 +319,22 @@ fn main() { println!("Here's a vector: {:?}", v); }); - handle.join(); + handle.join().unwrap(); } ``` Listing 16-3: Attempting to use a vector created by the main thread in another thread -The closure uses `v`, so will capture `v` and make it part of the closure’s +The closure uses `v`, so it will capture `v` and make it part of the closure’s environment. Because `thread::spawn` runs this closure in a new thread, we -should be able to access `v` inside that new thread. - -When we compile this example, however, we’ll get the following error: +should be able to access `v` inside that new thread. But when we compile this +example, we get the following error: ``` error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function - --> + --> src/main.rs:6:32 | 6 | let handle = thread::spawn(|| { | ^^ may outlive borrowed value `v` @@ -375,17 +342,19 @@ which is owned by the current function | - `v` is borrowed here | help: to force the closure to take ownership of `v` (and any other referenced -variables), use the `move` keyword, as shown: - | let handle = thread::spawn(move || { +variables), use the `move` keyword + | +6 | let handle = thread::spawn(move || { + | ^^^^^^^ ``` -Rust *infers* how to capture `v`, and since `println!` only needs a reference -to `v`, the closure tries to borrow `v`. There’s a problem, though: Rust can’t -tell how long the spawned thread will run, so doesn’t know if the reference to -`v` will always be valid. +Rust *infers* how to capture `v`, and because `println!` only needs a reference +to `v`, the closure tries to borrow `v`. However, there’s a problem: Rust can’t +tell how long the spawned thread will run, so it doesn’t know if the reference +to `v` will always be valid. -Let’s look at a scenario that’s more likely to have a reference to `v` that -won’t be valid, shown Listing 16-4: +Listing 16-4 provides a scenario that’s more likely to have a reference to `v` +that won’t be valid: Filename: src/main.rs @@ -401,33 +370,35 @@ fn main() { drop(v); // oh no! - handle.join(); + handle.join().unwrap(); } ``` Listing 16-4: A thread with a closure that attempts to capture a reference to `v` from a main thread that drops `v` -If we run this code, there’s a possibility the spawned thread will be -immediately put in the background without getting a chance to run at all. The -spawned thread has a reference to `v` inside, but the main thread immediately -drops `v`, using the `drop` function we discussed in Chapter 15. Then, when the +If we were allowed to run this code, there’s a possibility the spawned thread +will be immediately put in the background without running at all. The spawned +thread has a reference to `v` inside, but the main thread immediately drops +`v`, using the `drop` function we discussed in Chapter 15. Then, when the spawned thread starts to execute, `v` is no longer valid, so a reference to it is also invalid. Oh no! -To fix the problem in Listing 16-3, we can listen to the advice of the error -message: +To fix the compiler error in Listing 16-3, we can use the error message’s +advice: ``` help: to force the closure to take ownership of `v` (and any other referenced -variables), use the `move` keyword, as shown: - | let handle = thread::spawn(move || { +variables), use the `move` keyword + | +6 | let handle = thread::spawn(move || { + | ^^^^^^^ ``` By adding the `move` keyword before the closure, we force the closure to take -ownership of the values it’s using, rather than allowing Rust to infer that it -should borrow. The modification to Listing 16-3 shown in Listing 16-5 will -compile and run as we intend: +ownership of the values it’s using rather than allowing Rust to infer that it +should borrow the values. The modification to Listing 16-3 shown in Listing +16-5 will compile and run as we intend: Filename: src/main.rs @@ -441,26 +412,23 @@ fn main() { println!("Here's a vector: {:?}", v); }); - handle.join(); + handle.join().unwrap(); } ``` Listing 16-5: Using the `move` keyword to force a closure to take ownership of the values it uses - - - What would happen to the code in Listing 16-4 where the main thread called -`drop` if we use a `move` closure? Would `move` fix that case? Nope, we get a -different error, because what Listing 16-4 is trying to do isn’t allowed for a -different reason! If we add `move` to the closure, we’d move `v` into the -closure’s environment, and we could no longer call `drop` on it in the main -thread. We would get this compiler error instead: +`drop` if we use a `move` closure? Would `move` fix that case? Unfortunately, +no; we would get a different error because what Listing 16-4 is trying to do +isn’t allowed for a different reason. If we add `move` to the closure, we would +move `v` into the closure’s environment, and we could no longer call `drop` on +it in the main thread. We would get this compiler error instead: ``` error[E0382]: use of moved value: `v` - --> + --> src/main.rs:10:10 | 6 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -476,35 +444,26 @@ Rust’s ownership rules have saved us again! We got an error from the code in Listing 16-3 because Rust was being conservative and only borrowing `v` for the thread, which meant the main thread could theoretically invalidate the spawned thread’s reference. By telling Rust to move ownership of `v` to the spawned -thread, we’re guaranteeing to Rust that the main thread won’t use `v` anymore. -If we change Listing 16-4 in the same way, we’re then violating the ownership +thread, we’re guaranteeing Rust that the main thread won’t use `v` anymore. If +we change Listing 16-4 in the same way, we’re then violating the ownership rules when we try to use `v` in the main thread. The `move` keyword overrides Rust’s conservative default of borrowing; it doesn’t let us violate the ownership rules. - - - -Now that we have a basic understanding of threads and the thread API, let’s -talk about what we can actually *do* with threads. +With a basic understanding of threads and the thread API, let’s look at what we +can *do* with threads. ## Message Passing to Transfer Data Between Threads 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 slogan form from the Go language -documentation: +containing data. Here’s the idea in a slogan from the Go language documentation: > Do not communicate by sharing memory; instead, share memory by > communicating. > > --Effective Go at *http://golang.org/doc/effective_go.html* - - - One major tool Rust has for accomplishing message sending concurrency is the *channel*, a programming concept that Rust’s standard library provides an implementation of. You can imagine a channel in programming like a channel of @@ -512,20 +471,24 @@ water, such as a stream or a river. If you put something like a rubber duck or a boat into a stream, it will travel downstream to the end of the river. A channel in programming has two halves: a transmitter and a receiver. The -transmitter half is like the upstream location where we put rubber ducks into -the river, and the receiver half is the downstream place where the rubber duck -ends up. One part of our code calls methods on the transmitter with the data we -want to send, and another part checks the receiving end for arriving messages. +transmitter half is the upstream location where we put rubber ducks into the +river, and the receiver half is where the rubber duck ends up downstream. One +part of our code calls methods on the transmitter with the data we want to +send, and another part checks the receiving end for arriving messages. A +channel is said to be *closed* if either the transmitter or receiver half is +dropped. -Here we’ll work up to a program that has one thread to generate values and send -them down a channel, and another thread that will receive the values and print -them out. We’re going to be sending simple values between threads using a -channel for the purposes of illustration. Once you’re familiar with the -technique, you could use channels to implement a chat system, or a system where -many threads perform parts of a calculation and send the parts to one thread -that aggregates the results. +Here, we’ll work up to a program that has one thread to generate values and +send them down a channel, and another thread that will receive the values and +print them out. We’ll be sending simple values between threads using a channel +to illustrate the feature. Once you’re familiar with the technique, you could +use channels to implement a chat system or a system where many threads perform +parts of a calculation and send the parts to one thread that aggregates the +results. -First, we’ll create a channel but not do anything with it in Listing 16-6: +First, in Listing 16-6, we’ll create a channel but not do anything with it. +Note that this won’t compile yet because Rust can’t tell what type of values we +want to send over the channel: Filename: src/main.rs @@ -541,37 +504,27 @@ Listing 16-6: Creating a channel and assigning the two halves to `tx` and `rx` We create a new channel using the `mpsc::channel` function; `mpsc` stands for *multiple producer, single consumer*. In short, the way Rust’s standard library -has implemented channels is such that a channel can have multiple *sending* -ends that produce values, but only one *receiving* end that consumes those -values. Imagine multiple rivers and streams flowing together into one big -river: everything sent down any of the streams will end up in one river at the -end. We’re going to start with a single producer for now, but we’ll add -multiple producers once we get this example working. +implements channels means a channel can have multiple *sending* ends that +produce values but only one *receiving* end that consumes those values. Imagine +multiple rivers and streams flowing together into one big river: everything +sent down any of the streams will end up in one river at the end. We’ll start +with a single producer for now, but we’ll add multiple producers when we get +this example working. The `mpsc::channel` function returns a tuple, the first element of which is the -sending end and the second element the receiving end. The abbreviations `tx` +sending end and the second element is the receiving end. The abbreviations `tx` and `rx` are traditionally used in many fields for *transmitter* and *receiver* -respectively, so we give our variables those names to indicate each end. We’re -using a `let` statement with a pattern that destructures the tuples; we’ll be -discussing the use of patterns in `let` statements and destructuring in Chapter -18. Using a `let` statement in this way is a convenient way to extract the +respectively, so we name our variables as such to indicate each end. We’re +using a `let` statement with a pattern that destructures the tuples; we’ll +discuss the use of patterns in `let` statements and destructuring in Chapter +18. Using a `let` statement this way is a convenient approach to extract the pieces of the tuple returned by `mpsc::channel`. - - - Let’s move the transmitting end into a spawned thread and have it send one -string so that the spawned thread is communicating with the main thread, shown -in Listing 16-7. This is like putting a rubber duck in the river upstream or +string so the spawned thread is communicating with the main thread, as shown in +Listing 16-7. This is like putting a rubber duck in the river upstream or sending a chat message from one thread to another: - - - Filename: src/main.rs ``` @@ -590,21 +543,21 @@ fn main() { Listing 16-7: Moving `tx` to a spawned thread and sending “hi†-We’re again using `thread::spawn` to create a new thread, and then use `move` +Again, we’re using `thread::spawn` to create a new thread and then using `move` to move `tx` into the closure so the spawned thread owns `tx`. The spawned -thread needs to own the transmitting end of the channel in order to be able to -send messages through the channel. +thread needs to own the transmitting end of the channel to be able to send +messages through the channel. The transmitting end has a `send` method that takes the value we want to send. -The `send` method returns a `Result` type, so that if the receiving end -has already been dropped and there’s nowhere to send a value, the send -operation will error. In this example, we’re simply calling `unwrap` to panic -in case of error, but for a real application, we’d handle it properly--return -to Chapter 9 to review strategies for proper error handling. +The `send` method returns a `Result` type, so if the receiving end has +already been dropped and there’s nowhere to send a value, the send operation +will return an error. In this example, we’re calling `unwrap` to panic in case +of an error. But in a real application, we would handle it properly: return to +Chapter 9 to review strategies for proper error handling. In Listing 16-8, we’ll get the value from the receiving end of the channel in the main thread. This is like retrieving the rubber duck from the water at the -end of the river, or like getting a chat message: +end of the river or like getting a chat message: Filename: src/main.rs @@ -625,7 +578,7 @@ fn main() { } ``` -Listing 16-8: Receiving the value “hi†in the main thread and printing it out +Listing 16-8: Receiving the value “hi†in the main thread and printing it The receiving end of a channel has two useful methods: `recv` and `try_recv`. We’re using `recv`, short for *receive*, which will block the main thread’s @@ -634,29 +587,20 @@ sent, `recv` will return it in a `Result`. When the sending end of the channel closes, `recv` will return an error to signal that no more values will be coming. - - - The `try_recv` method doesn’t block, but will instead return a `Result` -immediately: an `Ok` value holding a message if one is available, and an `Err` +immediately: an `Ok` value holding a message if one is available and an `Err` value if there aren’t any messages this time. Using `try_recv` is useful if this thread has other work to do while waiting for messages: we could write a loop that calls `try_recv` every so often, handles a message if one is available, and otherwise does other work for a little while until checking again. -We’ve chosen to use `recv` in this example for simplicity; we don’t have any -other work for the main thread to do other than wait for messages, so blocking -the main thread is appropriate. +We’ve used `recv` in this example for simplicity; we don’t have any other work +for the main thread to do other than wait for messages, so blocking the main +thread is appropriate. - - - -If we run the code in Listing 16-8, we’ll see the value printed out from the -main thread: +When we run the code in Listing 16-8, we’ll see the value printed from the main +thread: ``` Got: hi @@ -666,21 +610,9 @@ Perfect! ### Channels and Ownership Transference - - - -The ownership rules play a vital role in message sending as far as helping us +The ownership rules play a vital role in message sending because they help us write safe, concurrent code. Preventing errors in concurrent programming is the -advantage we get by making the tradeoff of having to think about ownership +advantage we get by making the trade-off of having to think about ownership throughout our 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 @@ -706,15 +638,14 @@ fn main() { } ``` -Listing 16-9: Attempting to use `val` after we have sent it down the channel +Listing 16-9: Attempting to use `val` after we’ve sent it down the channel -Here, we try to print out `val` after we’ve sent it down the channel via -`tx.send`. Allowing this would be a bad idea: once the value has been sent to -another thread, that thread could modify or drop it before we try to use the -value again, which would potentially cause errors or unexpected results due to -inconsistent or nonexistent data. - -However, Rust gives us an error if we try to compile this code: +Here, we try to print `val` after we’ve sent it down the channel via `tx.send`. +Allowing this would be a bad idea: once the value has been sent to another +thread, that thread could modify or drop it before we try to use the value +again. Potentially, the other thread's modifications could cause errors or +unexpected results due to inconsistent or nonexistent data. However, Rust gives +us an error if we try to compile the code in Listing 16-9: ``` error[E0382]: use of moved value: `val` @@ -726,21 +657,21 @@ error[E0382]: use of moved value: `val` | ^^^ value used here after move | = note: move occurs because `val` has type `std::string::String`, which does - not implement the `Copy` trait +not implement the `Copy` trait ``` -Our concurrency mistake has caused a compile-time error! The `send` function -takes ownership of its parameter, and when the value is moved the receiver -takes ownership of it. This stops us from accidentally use the value again +Our concurrency mistake has caused a compile time error. The `send` function +takes ownership of its parameter, and when the value is moved, the receiver +takes ownership of it. This stops us from accidentally using the value again after sending it; the ownership system checks that everything is okay. ### Sending Multiple Values and Seeing the Receiver Waiting -The code in Listing 16-8 compiled and ran, but doesn’t show us very clearly -that two separate threads are talking to each other over the channel. In -Listing 16-10 we’ve made some modifications that will prove this code is +The code in Listing 16-8 compiled and ran, but it didn’t clearly show us that +two separate threads were talking to each other over the channel. In Listing +16-10 we’ve made some modifications that will prove the code in Listing 16-8 is running concurrently: the spawned thread will now send multiple messages and -pause for a second between each message. +pause for a second between each message: Filename: src/main.rs @@ -780,10 +711,10 @@ between each by calling the `thread::sleep` function with a `Duration` value of one second. In the main thread, we’re not calling the `recv` function explicitly anymore: -instead we’re treating `rx` as an iterator. For each value received, we’re -printing it out. When the channel is closed, iteration will end. +instead, we’re treating `rx` as an iterator. For each value received, we’re +printing it. When the channel is closed, iteration will end. -When running the code in Listing 16-10, you should see the following output, +When running the code in Listing 16-10, you should see the following output with a one second pause in between each line: ``` @@ -797,27 +728,18 @@ Because we don’t have any code that pauses or delays in the `for` loop in the main thread, we can tell that the main thread is waiting to receive values from the spawned thread. - - - ### Creating Multiple Producers by Cloning the Transmitter -Near the start of this section, we mentioned that `mpsc` stood for *multiple -producer, single consumer*. Let’s put that ability to use and expand the code -from Listing 16-10 to create multiple threads that all send values to the same -receiver. We can do that by cloning the transmitting half of the channel, as -shown in Listing 16-11: +Earlier we mentioned that `mpsc` was an acronym for *multiple* *producer, +single consumer*. Let’s put `mpsc` to use and expand the code in Listing 16-10 +to create multiple threads that all send values to the same receiver. We can do +so by cloning the transmitting half of the channel, as shown in Listing 16-11: Filename: src/main.rs ``` // --snip-- + let (tx, rx) = mpsc::channel(); let tx1 = mpsc::Sender::clone(&tx); @@ -848,10 +770,15 @@ thread::spawn(move || { thread::sleep(Duration::from_secs(1)); } }); + +for received in rx { + println!("Got: {}", received); +} + // --snip-- ``` -Listing 16-11: Sending multiple messages and pausing between each one +Listing 16-11: Sending multiple messages from multiple producers This time, before we create the first spawned thread, we call `clone` on the sending end of the channel. This will give us a new sending handle we can pass @@ -859,7 +786,7 @@ to the first spawned thread. We pass the original sending end of the channel to a second spawned thread. This gives us two threads, each sending different messages to the receiving end of the channel. -If you run this, you’ll *probably* see output like this: +When you run the code, you’ll *probably* see output like this: ``` Got: hi @@ -872,81 +799,66 @@ Got: thread Got: you ``` -You might see the values in a different order, it depends on your system! This -is what makes concurrency interesting as well as difficult. If you play around -with `thread::sleep`, giving it different values in the different threads, each -run will be more non-deterministic and create different output each time. +You might see the values in another order; it depends on your system. This is +what makes concurrency interesting as well as difficult. If you experiment with +`thread::sleep`, giving it various values in the different threads, each run +will be more non-deterministic and create different output each time. -Now that we’ve seen how channels work, let’s look at a different method of +Now that we’ve looked at how channels work, let’s look at a different method of concurrency. ## Shared State Concurrency -Message passing is a fine way of dealing with concurrency, but it’s not the -only one. Consider this slogan again: +Message passing is a fine way of handling concurrency, but it’s not the only +one. Consider this part of the slogan from the Go language documentation again: +“communicate by sharing memory.†-> Do not communicate by sharing memory; instead, share memory by -> communicating. +What would communicating by sharing memory look like? In addition, why would +message passing enthusiasts not use it and do the opposite instead? -What would “communicate by sharing memory†look like? And moreover, why would -message passing enthusiasts choose not to use it and do the opposite instead? - - - - -In a way, channels in any programming language are sort of like single -ownership, because once you transfer a value down a channel, you shouldn’t use -that value any longer. Shared memory concurrency is sort of like multiple -ownership: multiple threads can access the same memory location at the same -time. As we saw in Chapter 15 where multiple ownership was made possible by -smart pointers, multiple ownership can add additional complexity because these -different owners need managing. - -Rust’s type system and ownership rules assist a lot in getting this management -correct, though. For an example, let’s look at one of the more common -concurrency primitives for shared memory: mutexes. +In a way, channels in any programming language are similar to single ownership, +because once you transfer a value down a channel, you should no longer use that +value. Shared memory concurrency is like multiple ownership: multiple threads +can access the same memory location at the same time. As you saw in Chapter 15 +where smart pointers made multiple ownership possible, multiple ownership can +add additional complexity because these different owners need managing. Rust’s +type system and ownership rules greatly assist in getting this management +correct. For an example, let’s look at mutexes, one of the more common +concurrency primitives for shared memory. ### Mutexes Allow Access to Data from One Thread at a Time -A *mutex* is a concurrency primitive for sharing memory. It’s short for “mutual -exclusionâ€, as in, it only allows one thread to access some data at any given -time. In order to access the data in a mutex, a thread must first signal that -it wants access by asking to acquire the mutex’s *lock*. The lock is a data -structure that is part of the mutex that keeps track of who currently has -exclusive access to the data. We therefore describe the mutex as *guarding* the -data it holds via the locking system. +A *mutex* is an abbreviation for “mutual exclusion,†as in, it only allows one +thread to access some data at any given time. To access the data in a mutex, a +thread must first signal that it wants access by asking to acquire the mutex’s +*lock*. The lock is a data structure that is part of the mutex that keeps track +of who currently has exclusive access to the data. Therefore, we describe the +mutex as *guarding* the data it holds via the locking system. -Mutexes have a reputation for being hard to use because there are some -rules you have to remember: - - - +Mutexes have a reputation for being difficult to use because you have to +remember two rules: 1. You must attempt to acquire the lock before using the data. -2. Once you’re done with the data that’s guarded by the mutex, you must unlock - the data so other threads can acquire the lock. +2. When you’re done with the data that the mutex guards, you must unlock the + data so other threads can acquire the lock. For a real-world metaphor of a mutex, imagine a panel discussion at a -conference with only one microphone. Before a panelist may speak, they have to -ask or signal that they would like to use the microphone. Once they get the -microphone, they may talk for as long as they would like, then hand the +conference with only one microphone. Before a panelist can speak, they have to +ask or signal that they want to use the microphone. When they get the +microphone, they can talk for as long as they want to and then hand the microphone to the next panelist who requests to speak. If a panelist forgets to hand the microphone off when they’re finished with it, no one else is able to -speak. If management of the shared microphone goes wrong, the panel would not +speak. If management of the shared microphone goes wrong, the panel wouldn’t work as planned! -Management of mutexes can be incredibly tricky to get right, and that’s why so +Management of mutexes can be incredibly tricky to get right, which is why so many people are enthusiastic about channels. However, thanks to Rust’s type system and ownership rules, we can’t get locking and unlocking wrong. #### The API of `Mutex` -Let’s start simply with an example of using a mutex in a single-threaded -context, shown in Listing 16-12: +As an example of how to use a mutex, let’s start by using a mutex in a +single-threaded context, as shown in Listing 16-12: Filename: src/main.rs @@ -965,49 +877,42 @@ fn main() { } ``` -Listing 16-12: Exploring the API of `Mutex` in a single threaded context for +Listing 16-12: Exploring the API of `Mutex` in a single-threaded context for simplicity As with many types, we create a `Mutex` using the associated function `new`. To access the data inside the mutex, we use the `lock` method to acquire the -lock. This call will block the current thread so that it can’t do any work -until it’s our turn to have the lock. - - - +lock. This call will block the current thread so it can’t do any work until +it’s our turn to have the lock. The call to `lock` would fail if another thread holding the lock panicked. In that case, no one would ever be able to get the lock, so we’ve chosen to `unwrap` and have this thread panic if we’re in that situation. - - - -Once we’ve acquired the lock, we can treat the return value, named `num` in +After we’ve acquired the lock, we can treat the return value, named `num` in this case, as a mutable reference to the data inside. The type system ensures -that we acquire a lock before using this value: `Mutex` is not an `i32`, -so we *must* acquire the lock in order to be able to use the `i32` value. We -can’t forget; the type system won’t let us do it otherwise. +that we acquire a lock before using the value in `m`: `Mutex` is not an +`i32`, so we *must* acquire the lock to be able to use the `i32` value. We +can’t forget; the type system won’t let us access the inner `i32` otherwise. -As you may suspect, `Mutex` is a smart pointer. More accurately, the call to -`lock` *returns* a smart pointer called `MutexGuard`. This smart pointer -implements `Deref` to point at our inner data, and also has a `Drop` -implementation that releases the lock automatically when `MutexGuard` goes out -of scope, which happens at the end of the inner scope in Listing 16-12. This -way, we don’t risk forgetting to release the lock and blocking it from use by -other threads, because it happens automatically. +As you might suspect, `Mutex` is a smart pointer. More accurately, the call +to `lock` *returns* a smart pointer called `MutexGuard`. This smart pointer +implements `Deref` to point at our inner data; the smart pointer also has a +`Drop` implementation that releases the lock automatically when a `MutexGuard` +goes out of scope, which happens at the end of the inner scope in Listing +16-12. As a result, we don’t risk forgetting to release the lock and blocking +the mutex from being used by other threads because the lock release happens +automatically. -After dropping the lock, we can print out the mutex value and see that we were -able to change the inner `i32` to 6. +After dropping the lock, we can print the mutex value and see that we were able +to change the inner `i32` to 6. #### Sharing a `Mutex` Between Multiple Threads -Let’s now try to share a value between multiple threads using `Mutex`. We’ll -spin up ten threads, and have them each increment a counter value by 1 so that +Now, let’s try to share a value between multiple threads using `Mutex`. +We’ll spin up 10 threads and have them each increment a counter value by 1, so the counter goes from 0 to 10. Note that the next few examples will have -compiler errors, and we’re going to use those errors to learn more about using +compiler errors, and we’ll use those errors to learn more about using `Mutex` and how Rust helps us use it correctly. Listing 16-13 has our starting example: @@ -1040,29 +945,24 @@ fn main() { Listing 16-13: Ten threads each increment a counter guarded by a `Mutex` -We’re creating a `counter` variable to hold an `i32` inside a `Mutex`, like -we did in Listing 16-12. Next, we’re creating 10 threads by mapping over a -range of numbers. We use `thread::spawn` and give all the threads the same -closure, one that moves the counter into the thread, acquires a lock on the -`Mutex` by calling the `lock` method, and then adds 1 to the value in the -mutex. When a thread finishes running its closure, `num` will go out of scope -and release the lock so another thread can acquire it. +We’re creating a `counter` variable to hold an `i32` inside a `Mutex`, as we +did in Listing 16-12. Next, we’re creating 10 threads by mapping over a range +of numbers. We use `thread::spawn` and give all the threads the same closure, +one that moves the counter into the thread, acquires a lock on the `Mutex` +by calling the `lock` method, and then adds 1 to the value in the mutex. When a +thread finishes running its closure, `num` will go out of scope and release the +lock so another thread can acquire it. -In the main thread, we collect all the join handles like we did in Listing -16-2, and then call `join` on each to make sure all the threads finish. At that -point, the main thread will acquire the lock and print out the result of this +In the main thread, we collect all the join handles, as we did in Listing 16-2, +and then call `join` on each to make sure all the threads finish. At that +point, the main thread will acquire the lock and print the result of this program. We hinted that this example won’t compile, now let’s find out why! - - - ``` error[E0382]: capture of moved value: `counter` - --> + --> src/main.rs:10:27 | 9 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -1073,7 +973,7 @@ error[E0382]: capture of moved value: `counter` which does not implement the `Copy` trait error[E0382]: use of moved value: `counter` - --> + --> src/main.rs:21:29 | 9 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -1087,14 +987,13 @@ error[E0382]: use of moved value: `counter` error: aborting due to 2 previous errors ``` -The error message is saying that the `counter` value is moved into the closure, -then is captured when we call `lock`. That sounds like what we wanted, but it’s -not allowed! +The error message states that the `counter` value is moved into the closure and +then is captured when we call `lock`. That description sounds like what we +wanted, but it’s not allowed! -Let’s reason this out by simplifying the program. Instead of making 10 threads +Let’s figure this out by simplifying the program. Instead of making 10 threads in a `for` loop, let’s just make two threads without a loop and see what -happens then. Replace the first `for` loop in Listing 16-13 with this code -instead: +happens. Replace the first `for` loop in Listing 16-13 with this code instead: ``` let handle = thread::spawn(move || { @@ -1113,11 +1012,12 @@ handles.push(handle2); ``` We make two threads and change the variable names used with the second thread -to `handle2` and `num2`. When we run this time, compiling gives us: +to `handle2` and `num2`. When we run the code this time, compiling gives us the +following: ``` error[E0382]: capture of moved value: `counter` - --> + --> src/main.rs:16:24 | 8 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -1129,7 +1029,7 @@ error[E0382]: capture of moved value: `counter` which does not implement the `Copy` trait error[E0382]: use of moved value: `counter` - --> + --> src/main.rs:26:29 | 8 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -1143,23 +1043,23 @@ error[E0382]: use of moved value: `counter` error: aborting due to 2 previous errors ``` -Aha! The first error message tells us that `counter` is moved into the closure +Aha! The first error message indicates that `counter` is moved into the closure for the thread associated with `handle`. That move is preventing us from capturing `counter` when we try to call `lock` on it and store the result in `num2` in the second thread! So Rust is telling us that we can’t move ownership -of `counter` into multiple threads. This was hard to see before because our +of `counter` into multiple threads. This was hard to see earlier because our threads were in a loop, and Rust can’t point to different threads in different -iterations of the loop. Let’s try to fix this with a multiple-ownership method -we saw in Chapter 15. +iterations of the loop. Let’s fix the compiler error with a multiple-ownership +method we discussed in Chapter 15. #### Multiple Ownership with Multiple Threads -In Chapter 15, we were able to give a value multiple owners by using the smart -pointer `Rc` to create a reference-counted value. Let’s try to do the same -here and see what happens. We’ll wrap the `Mutex` in `Rc` in Listing -16-14, and clone the `Rc` before moving ownership to the thread. Now we’ve -seen the errors, we’ll also switch back to using the `for` loop, and we’ll keep -the `move` keyword with the closure: +In Chapter 15, we gave a value multiple owners by using the smart pointer +`Rc` to create a reference-counted value. Let’s do the same here and see +what happens. We’ll wrap the `Mutex` in `Rc` in Listing 16-14 and clone +the `Rc` before moving ownership to the thread. Now that we’ve seen the +errors, we’ll also switch back to using the `for` loop, and we’ll keep the +`move` keyword with the closure: Filename: src/main.rs @@ -1173,7 +1073,7 @@ fn main() { let mut handles = vec![]; for _ in 0..10 { - let counter = Rc::clone(&counter); + let counter = Rc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); @@ -1194,66 +1094,65 @@ Listing 16-14: Attempting to use `Rc` to allow multiple threads to own the `Mutex` Once again, we compile and get... different errors! The compiler is teaching us -a lot! +a lot. ``` error[E0277]: the trait bound `std::rc::Rc>: -std::marker::Send` is not satisfied - --> +std::marker::Send` is not satisfied in `[closure@Filename: src/main.rs:11:36: +15:10 +counter:std::rc::Rc>]` + --> src/main.rs:11:22 | 11 | let handle = thread::spawn(move || { - | ^^^^^^^^^^^^^ the trait `std::marker::Send` is not - implemented for `std::rc::Rc>` + | ^^^^^^^^^^^^^ `std::rc::Rc>` +cannot be sent between threads safely | - = note: `std::rc::Rc>` cannot be sent between threads - safely + = help: within `[closure@Filename: src/main.rs:11:36: 15:10 +counter:std::rc::Rc>]`, the trait `std::marker::Send` is +not implemented for `std::rc::Rc>` = note: required because it appears within the type - `[closure@src/main.rs:11:36: 15:10 - counter:std::rc::Rc>]` +`[closure@Filename: src/main.rs:11:36: 15:10 +counter:std::rc::Rc>]` = note: required by `std::thread::spawn` ``` -Wow, that’s quite wordy! Here are some important parts to pick out: the first -note says `Rc> cannot be sent between threads safely`. The reason -for this is in the error message, which, once distilled, says `the trait bound -Send is not satisfied`. We’re going to talk about `Send` in the next section; -it’s one of the traits that ensures the types we use with threads are meant for -use in concurrent situations. - - - +Wow, that error message is very wordy! Here are some important parts to focus +on: the first inline error says `` `std::rc::Rc>` cannot +be sent between threads safely ``. The reason for this is in the next important +part to focus on, the error message. The distilled error message says `` the +trait bound `Send` is not satisfied ``. We’ll talk about `Send` in the next +section: it’s one of the traits that ensures the types we use with threads are +meant for use in concurrent situations. Unfortunately, `Rc` is not safe to share across threads. When `Rc` manages the reference count, it adds to the count for each call to `clone` and -subtracts from the count when each clone is dropped, but it doesn’t use any +subtracts from the count when each clone is dropped. But it doesn’t use any concurrency primitives to make sure that changes to the count can’t be -interrupted by another thread. This could lead to wrong counts: subtle bugs -that could in turn lead to memory leaks or a value being dropped before we’re -done with it. What we need is a type exactly like `Rc`, but that makes -changes to the reference count in a thread-safe way. +interrupted by another thread. This could lead to wrong counts—subtle bugs that +could in turn lead to memory leaks or a value being dropped before we’re done +with it. What we need is a type exactly like `Rc` but one that makes changes +to the reference count in a thread-safe way. #### Atomic Reference Counting with `Arc` -Luckily for us, there *is* a type like `Rc` that’s safe to use in concurrent -situations: `Arc`. The ‘a’ stands for *atomic*, meaning it’s an *atomically +Fortunately, `Arc` *is* a type like `Rc` that is safe to use in +concurrent situations. The ‘a’ stands for *atomic*, meaning it’s an *atomically reference counted* type. Atomics are an additional kind of concurrency -primitive that we won’t cover in detail here; see the standard library -documentation for `std::sync::atomic` for more details. What you need to know -here is that atomics work like primitive types, but are safe to share across -threads. +primitive that we won’t cover in detail here: see the standard library +documentation for `std::sync::atomic` for more details. At this point, you just +need to know that atomics work like primitive types but are safe to share +across threads. -You might then wonder why all primitive types aren’t atomic, and why standard +You might then wonder why all primitive types aren’t atomic and why standard library types aren’t implemented to use `Arc` by default. The reason is that thread safety comes with a performance penalty that you only want to pay when -you really need to. If you’re only doing operations on values within a single -thread, your code can run faster if it doesn’t have to enforce the guarantees -atomics provide. +you really need to. If you’re just performing operations on values within a +single thread, your code can run faster if it doesn’t have to enforce the +guarantees atomics provide. -Back to our example: `Arc` and `Rc` have the same API, so we fix our -program by changing the `use` line and the call to `new`. The code in Listing -16-15 will finally compile and run: +Let’s return to our example: `Arc` and `Rc` have the same API, so we fix +our program by changing the `use` line and the call to `new`. The code in +Listing 16-15 will finally compile and run: Filename: src/main.rs @@ -1266,7 +1165,7 @@ fn main() { let mut handles = vec![]; for _ in 0..10 { - let counter = Arc::clone(&counter); + let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); @@ -1286,79 +1185,68 @@ fn main() { Listing 16-15: Using an `Arc` to wrap the `Mutex` to be able to share ownership across multiple threads -This will print: +This code will print the following: ``` Result: 10 ``` We did it! We counted from 0 to 10, which may not seem very impressive, but it -did teach us a lot about `Mutex` and thread safety! This structure could -also be used to do more complicated operations than just incrementing a -counter: these methods allow us to divide calculations up into independent -parts, which we could split across threads, and then we can use a `Mutex` to -have each thread update the final result with its part. +did teach us a lot about `Mutex` and thread safety. You could also use this +program’s structure to do more complicated operations than just incrementing a +counter. Using this strategy, you can divide a calculation into independent +parts, split those parts across threads, then use a `Mutex` to have each +thread update the final result with its part. -### Similarities between `RefCell`/`Rc` and `Mutex`/`Arc` +### Similarities Between `RefCell`/`Rc` and `Mutex`/`Arc` -You may have noticed that `counter` is immutable but we could get a mutable +You might have noticed that `counter` is immutable, but we could get a mutable reference to the value inside it; this means `Mutex` provides interior mutability, like the `Cell` family does. In the same way we used `RefCell` in Chapter 15 to allow us to mutate contents inside an `Rc`, we use -`Mutex` to mutate contents inside of an `Arc`. +`Mutex` to mutate contents inside an `Arc`. -Another thing to note is that Rust can’t prevent us from all kinds of logic -errors when using `Mutex`. Recall from Chapter 15 that using `Rc` came +Another detail to note is that Rust can’t protect us from all kinds of logic +errors when we use `Mutex`. Recall in Chapter 15 that using `Rc` came with the risk of creating reference cycles, where two `Rc` values refer to -each other, causing memory leaks. Similarly, `Mutex` comes the risk of -*deadlocks*. These occur when an operation needs to lock two resources and two -threads have each acquired one of the locks, causing them to wait for each -other forever. If you’re interested in this topic, try creating a Rust program -that has a deadlock, then research deadlock mitigation strategies for mutexes -in any language, and have a go at implementing them in Rust. The standard -library API documentation for `Mutex` and `MutexGuard` will have useful -information. +each other, causing memory leaks. Similarly, `Mutex` comes with the risk of +creating *deadlocks*. These occur when an operation needs to lock two resources +and two threads have each acquired one of the locks, causing them to wait for +each other forever. If you’re interested in deadlocks, try creating a Rust +program that has a deadlock; then research deadlock mitigation strategies for +mutexes in any language and have a go at implementing them in Rust. The +standard library API documentation for `Mutex` and `MutexGuard` offers +useful information. - - - - -Let’s round out this chapter by talking about the `Send` and `Sync` traits and -how we could use them with custom types. +We’ll round out this chapter by talking about the `Send` and `Sync` traits, and +how we can use them with custom types. ## Extensible Concurrency with the `Sync` and `Send` Traits -Interestingly, the Rust language itself knows *very* little about concurrency. -Almost everything we’ve talked about so far in this chapter has been part of -the standard library, not the language. Our concurrency options are not limited -to the language or the standard library, meaning we can write our own -concurrency options or use ones others have written. +Interestingly, the Rust language has *very* few concurrency features. Almost +every concurrency feature we’ve talked about so far in this chapter has been +part of the standard library, not the language. Our options for handling +concurrency are not limited to the language or the standard library; we can +write our own concurrency features or use those written by others. -There *are* two concurrency concepts embedded in the language, however: the +However, two concurrency concepts are embedded in the language: the `std::marker` traits `Sync` and `Send`. ### Allowing Transference of Ownership Between Threads with `Send` The `Send` marker trait indicates that ownership of the type implementing -`Send` may be transferred between threads. Almost every Rust type is `Send`, +`Send` can be transferred between threads. Almost every Rust type is `Send`, but there are some exceptions, including `Rc`: this cannot be `Send` because if we cloned an `Rc` value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time. For this reason, `Rc` is implemented for use in single-threaded situations -where you don’t want to pay the threadsafe performance penalty. +where you don’t want to pay the thread-safe performance penalty. -In this way Rust’s type system and trait bounds ensure we can never +Therefore, Rust’s type system and trait bounds ensure that we can never accidentally send an `Rc` value across threads unsafely. When we tried to do -this in Listing 16-14, we got an error that said `the trait Send is not -implemented for Rc>`. When we switched to `Arc`, which is `Send`, -the code compiled. +this in Listing 16-14, we got the error `the trait Send is not implemented for +Rc>`. When we switched to `Arc`, which is `Send`, the code +compiled. Any type composed entirely of `Send` types is automatically marked as `Send` as well. Almost all primitive types are `Send`, aside from raw pointers, which @@ -1367,52 +1255,55 @@ we’ll discuss in Chapter 19. ### Allowing Access from Multiple Threads with `Sync` The `Sync` marker trait indicates that it is safe for the type implementing -`Sync` to be referenced from multiple threads. Another way to say this is that -any type `T` is `Sync` if `&T` (a reference to `T`) is `Send`, meaning the -reference can be sent safely to another thread. In a similar manner as `Send`, -primitive types are `Sync` and types composed entirely of types that are `Sync` -are also `Sync`. +`Sync` to be referenced from multiple threads. In other words, any type `T` is +`Sync` if `&T` (a reference to `T`) is `Send`, meaning the reference can be +sent safely to another thread. Similar to `Send`, primitive types are `Sync` +and types composed entirely of types that are `Sync` are also `Sync`. -`Rc` is also not `Sync`, for the same reasons that it’s not `Send`. -`RefCell` (which we talked about in Chapter 15) and the family of related -`Cell` types are not `Sync`. The implementation of borrow checking that -`RefCell` does at runtime is not threadsafe. `Mutex` is `Sync`, and can -be used to share access with multiple threads as we saw in the previous section. +The smart pointer `Rc` is also not `Sync` for the same reasons that it’s not +`Send`. The `RefCell` type (which we talked about in Chapter 15) and the +family of related `Cell` types are not `Sync`. The implementation of borrow +checking that `RefCell` does at runtime is not thread-safe. The smart +pointer `Mutex` is `Sync` and can be used to share access with multiple +threads, as you saw in the “Sharing a `Mutex` Between Multiple Threads†+section. -### Implementing `Send` and `Sync` Manually is Unsafe +### Implementing `Send` and `Sync` Manually Is Unsafe Because types that are made up of `Send` and `Sync` traits are automatically -also `Send` and `Sync`, we don’t have to implement those traits ourselves. As +also `Send` and `Sync`, we don’t have to implement those traits manually. As marker traits, they don’t even have any methods to implement. They’re just -useful for enforcing concurrency-related invariants. +useful for enforcing invariants related to concurrency. Manually implementing these traits involves implementing unsafe Rust code. -We’re going to be talking about using unsafe Rust code in Chapter 19; for now, -the important information is that building new concurrent types not made up of -`Send` and `Sync` parts requires careful thought, in order to uphold the safety -guarantees. The Nomicon at *https://doc.rust-lang.org/stable/nomicon/* -has more information about these guarantees and how to uphold them. +We’ll talk about using unsafe Rust code in Chapter 19; for now, the important +information is that building new concurrent types not made up of `Send` and +`Sync` parts requires careful thought to uphold the safety guarantees. The +Rustonomicon at *https://doc.rust-lang.org/stable/nomicon/* has more +information about these guarantees and how to uphold them. ## Summary -This isn’t the last we’ll see of concurrency in this book; the project in -Chapter 20 will use these concepts in a more realistic situation than the -smaller examples discussed here. +This isn’t the last you’ll see of concurrency in this book: the project in +Chapter 20 will use the concepts examined in this chapter in a more realistic +situation than the smaller examples discussed here. -As we mentioned, since very little of how Rust deals with concurrency is part -of the language, many concurrency solutions are implemented as crates. These -evolve more quickly than the standard library; search online for the current -state-of-the-art crates to use in multithreaded situations. +As mentioned earlier, because very little of how Rust handles concurrency is +part of the language, many concurrency solutions are implemented as crates. +These evolve more quickly than the standard library, so be sure to search +online for the current, state-of-the-art crates to use in multithreaded +situations. -Rust provides channels for message passing and smart pointer types like -`Mutex` and `Arc` that are safe to use in concurrent contexts. The type -system and the borrow checker will make sure the code using these solutions -won’t end up with data races or invalid references. Once we get our code -compiling, we can rest assured that it will happily run on multiple threads -without the kinds of hard-to-track-down bugs common in other languages. -Concurrent programming is no longer something to be afraid of: go forth and -make your programs concurrent, fearlessly! +The Rust standard library provides channels for message passing and smart +pointer types, such as `Mutex` and `Arc`, that are safe to use in +concurrent contexts. The type system and the borrow checker ensure that the +code using these solutions won’t end up with data races or invalid references. +Once we get our code to compile, we can rest assured that it will happily run +on multiple threads without the kinds of hard-to-track-down bugs common in +other languages. Concurrent programming is no longer a concept to be afraid of: +go forth and make your programs concurrent, fearlessly! + +Next, we’ll talk about idiomatic ways to model problems and structure solutions +as your Rust programs get bigger. In addition, we’ll discuss how Rust’s idioms +relate to those you might be familiar with from object oriented programming. -Next, let’s talk about idiomatic ways to model problems and structure solutions -as your Rust programs get bigger, and how Rust’s idioms relate to those you -might be familiar with from Object Oriented Programming. diff --git a/src/doc/book/second-edition/nostarch/chapter19.md b/src/doc/book/second-edition/nostarch/chapter19.md index e7c3c5e71c..68c4e6d2b1 100644 --- a/src/doc/book/second-edition/nostarch/chapter19.md +++ b/src/doc/book/second-edition/nostarch/chapter19.md @@ -1,22 +1,34 @@ [TOC] + + + # Advanced Features -We’ve come a long way! By now, we’ve learned 99% of the things you’ll need to +We’ve come a long way! By now, you’ve learned 99% of the things you’ll need to know when writing Rust. Before we do one more project in Chapter 20, let’s talk -about a few things that you may run into that last 1% of the time. Feel free to -skip this chapter and come back to it once you run into these things in the -wild; the features we’ll learn to use here are useful in very specific +about a few things you may run into that last 1% of the time. Feel free to use +this chapter as a reference for when you run into something unknown in the +wild; the features you’ll learn to use here are useful in very specific situations. We don’t want to leave these features out, but you won’t find yourself reaching for them often. In this chapter, we’re going to cover: * Unsafe Rust: for when you need to opt out of some of Rust’s guarantees and - tell the compiler that you will be responsible for upholding the guarantees - instead -* Advanced Lifetimes: Additional lifetime syntax for complex situations + make yourself responsible for upholding the guarantees instead +* 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: some more about the newtype pattern, type aliases, the @@ -27,94 +39,99 @@ It’s a panoply of Rust features with something for everyone! Let’s dive in! ## Unsafe Rust -In all of the previous chapters in this book, we’ve been discussing code -written in Rust that has memory safety guarantees enforced at compile time. -However, Rust has a second language hiding out inside of it, unsafe Rust, which -does not enforce these memory safety guarantees. Unsafe Rust works just like -regular Rust does, but it gives you extra superpowers not available in safe -Rust code. +All the code we’ve discussed so far has had Rust’s memory safety guarantees +enforced at compile time. However, Rust has a second language hiding inside of +it that does not enforce these memory safety guarantees: unsafe Rust. This +works just like regular Rust, but gives you extra superpowers. Unsafe Rust exists because, by nature, static analysis is conservative. When -trying to determine if code upholds some guarantees or not, it’s better to -reject some programs that are valid than it is to accept some programs that are -invalid. There are some times when your code might be okay, but Rust thinks -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’re on your own; if you get -unsafe code wrong, problems due to memory unsafety like null pointer -dereferencing can occur. +the compiler is trying to determine if code upholds the guarantees or not, it’s +better for it to reject some programs that are valid than accept some programs +that are invalid. That inevitably means there are some times when your code +might be okay, but Rust thinks 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’re on your own; if you get unsafe code wrong, problems due to memory +unsafety, like null pointer dereferencing, can occur. -There’s another reason that Rust needs to have unsafe code: the underlying -hardware of computers is inherently not safe. If Rust didn’t let you do unsafe -operations, there would be some tasks that you simply could not do. But Rust -needs to be able to let you do low-level systems programming like directly -interacting with your operating system, or even writing your own operating -system! That’s part of the goals of the language. We need some way to do these -kinds of things. +There’s another reason Rust has an unsafe alter ego: the underlying hardware of +computers is inherently not safe. If Rust didn’t let you do unsafe operations, +there would be some tasks that you simply could not do. Rust needs to allow you +to do low-level systems programming like directly interacting with your +operating system, or even writing your own operating system! That’s one of the +goals of the language. Let’s see what you can do with unsafe Rust, and how to +do it. ### Unsafe Superpowers -We switch into unsafe Rust by using the `unsafe` keyword and starting a new -block that holds the unsafe code. There are four actions that you can take in -unsafe Rust that you can’t in safe Rust. We call these the “unsafe -superpowers.†We haven’t seen most of these features yet since they’re only -usable with `unsafe`! +To switch into unsafe Rust we use the `unsafe` keyword, and then we can start a +new block that holds the unsafe code. There are four actions that you can take +in unsafe Rust that you can’t in safe Rust that we call “unsafe superpowers.†+Those superpowers are the ability to: -1. Dereferencing a raw pointer -2. Calling an unsafe function or method -3. Accessing or modifying a mutable static variable -4. Implementing an unsafe trait +1. Dereference a raw pointer +2. Call an unsafe function or method +3. Access or modify a mutable static variable +4. Implement an unsafe trait 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 only thing the `unsafe` keyword does is -give you access to these four features that aren’t checked by the compiler for -memory safety. You still get some degree of safety inside of an unsafe block! -Furthermore, `unsafe` does not mean the code inside the block is dangerous or -definitely will have memory safety problems: the intent is that you as the -programmer will ensure that the code inside an `unsafe` block will have valid -memory, since you’ve turned off the compiler checks. +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. You still get some degree of safety inside of an unsafe block! -People are fallible, however, and mistakes will happen. By requiring these four -unsafe operations to be inside blocks annotated with `unsafe`, if you make a -mistake and get an error related to memory safety, you’ll know that it has to -be related to one of the places that you opted into this unsafety. That makes -the cause of memory safety bugs much easier to find, since we know Rust is -checking all of the other code for us. To get this benefit of only having a few -places to investigate memory safety bugs, it’s important to contain your unsafe -code to as small of an area as possible. Any code inside of an `unsafe` block -is suspect when debugging a memory problem: keep `unsafe` blocks small and -you’ll thank yourself later since you’ll have less code to investigate. +Furthermore, `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 you as the programmer will ensure the code inside an `unsafe` block will +access memory in a valid way. -In order to isolate unsafe code as much as possible, it’s a good idea to -enclose unsafe code within a safe abstraction and provide a safe API, which -we’ll be discussing once we get into unsafe functions and methods. Parts of the -standard library are implemented as safe abstractions over unsafe code that has -been audited. This prevents uses of `unsafe` from leaking out into all the +People are fallible, and mistakes will happen, but by requiring these four +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 and you’ll thank yourself later when you go to +investigate memory bugs. + +To isolate unsafe code as much as possible, it’s a good idea to enclose unsafe +code within a safe abstraction and provide a safe API, which we’ll be +discussing once we get into unsafe functions and methods. Parts of the standard +library are implemented as safe abstractions over unsafe code that has been +audited. This technique prevents uses of `unsafe` from leaking out into all the places that you or your users might want to make use of the functionality -implemented with `unsafe` code, since using a safe abstraction is safe. +implemented with `unsafe` code, because using a safe abstraction is safe. Let’s talk about each of the four unsafe superpowers in turn, and along the way we’ll look at some abstractions that provide a safe interface to unsafe code. ### Dereferencing a Raw Pointer -Way back in Chapter 4, we first learned about references. We also learned that -the compiler ensures that references are always valid. Unsafe Rust has two new -types similar to references called *raw pointers*. Just like references, we can -have an immutable raw pointer and a mutable raw pointer, written as `*const T` -and `*mut T`, respectively. In the context of raw pointers, “immutable†means -that the pointer can’t be directly assigned to after being dereferenced. +Way back in Chapter 4, in the “Dangling References†section, we covered that +the compiler ensures references are always valid. Unsafe Rust has two new types +similar to references called *raw pointers*. Just like with references, raw +pointers can be immutable or mutable, 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 +can’t be directly assigned to after being dereferenced. -Raw pointers are different than references and smart pointers in a few ways. -Raw pointers: +Different from references and smart pointers, keep in mind that raw pointers: -- Are allowed to ignore the borrowing rules and have both immutable and a - mutable pointer or multiple mutable pointers to the same location +- Are allowed to ignore the borrowing rules and have both immutable and + mutable pointers, or multiple mutable pointers to the same location - Aren’t guaranteed to point to valid memory - Are allowed to be null - Don’t implement any automatic clean-up -Listing 19-1 shows how to create raw pointers from references: +By opting out of having Rust enforce these guarantees, you are able to make the +tradeoff of giving up guaranteed safety to gain 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 both an immutable and a mutable raw pointer +from references. ``` let mut num = 5; @@ -125,19 +142,27 @@ let r2 = &mut num as *mut i32; Listing 19-1: Creating raw pointers from references -The `*const T` type is an immutable raw pointer, and `*mut T` is a mutable raw -pointer. We’ve created raw pointers by using `as` to cast an immutable and a -mutable reference into their corresponding raw pointer types. These particular -raw pointers will be valid since we created them directly from references that -are guaranteed to be valid, but we can’t make that assumption about any raw -pointer. + + +Notice we don’t include the `unsafe` keyword here---you can *create* raw +pointers in safe code, you just can’t *dereference* raw pointers outside of an +unsafe block, as we’ll see in a bit. + +We’ve created raw pointers by using `as` to cast an immutable and a mutable +reference into their corresponding raw pointer types. Because we created them +directly from references that are guaranteed to be valid, we can know that +these particular raw pointers are valid, but we can’t make that assumption +about just any raw pointer. + +Next we’ll create a raw pointer whose validity we can’t be so certain of. Listing 19-2 shows how to create a raw pointer to an arbitrary location in memory. Trying to use arbitrary memory is undefined: there may be data at that -address, there may not be any data at that address, the compiler might optimize -the code so that there is no memory access, or your program might segfault. -There’s not usually a good reason to be writing code like this, but it is -possible: +address or there may not, the compiler might optimize the code so that there is +no memory access, or your program might segfault. There’s not usually a good +reason to be writing code like this, but it is possible: ``` let address = 0x012345usize; @@ -146,10 +171,10 @@ let r = address as *const i32; Listing 19-2: Creating a raw pointer to an arbitrary memory address -Note there’s no `unsafe` block in either Listing 19-1 or 19-2. You can *create* -raw pointers in safe code, but you can’t *dereference* raw pointers and read -the data being pointed to. Using the dereference operator, `*`, on a raw -pointer requires an `unsafe` block, as shown in Listing 19-3: +Remember that we said you can create raw pointers in safe code, but you can’t +*dereference* raw pointers and read the data being pointed to. We’ll do so now +using the dereference operator, `*`, on a raw pointer, which does require an +`unsafe` block, as shown in Listing 19-3: ``` let mut num = 5; @@ -168,27 +193,38 @@ Listing 19-3: Dereferencing raw pointers within an `unsafe` block Creating a pointer can’t do any harm; it’s only when accessing the value that it points at that you might end up dealing with an invalid value. -Note also that in Listing 19-1 and 19-3 we created a `*const i32` and a `*mut -i32` that both pointed to the same memory location, that of `num`. If we had -tried to create an immutable and a mutable reference to `num` instead of raw -pointers, this would not have compiled due to the rule that says we can’t have -a mutable reference at the same time as any immutable references. With raw +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, that of `num`. If +instead we’d tried to create an immutable and a mutable reference to `num`, +this 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 are able to 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! With all of these dangers, why would we ever use raw pointers? One major use -case is interfacing with C code, as we’ll see in the next section on unsafe -functions. Another case is to build up safe abstractions that the borrow -checker doesn’t understand. Let’s introduce unsafe functions then look at an -example of a safe abstraction that uses unsafe code. +case is when interfacing with C code, as we’ll see in the next section on +unsafe functions. Another case is when building up safe abstractions that the +borrow checker doesn’t understand. Let’s introduce unsafe functions then look +at an example of a safe abstraction that uses unsafe code. ### Calling an Unsafe Function or Method -The second operation that requires an unsafe block is calling an unsafe -function. Unsafe functions and methods look exactly like regular functions and -methods, but they have an extra `unsafe` out front. Bodies of unsafe functions -are effectively `unsafe` blocks. Here’s an unsafe function named `dangerous`: +The second type of operation that requires an unsafe block is calls to unsafe +functions. Unsafe functions and methods look exactly like regular functions and +methods, but they have an extra `unsafe` out front. That `unsafe` indicates the +function has requirements we as programmers need to uphold when we call this +function, because Rust can’t guarantee we’ve met these requirements. By calling +an unsafe function within an `unsafe` block, we are saying that we’ve read this +function’s documentations and take responsibility for upholding the function’s +contracts ourselves. + + + + +Here’s an unsafe function named `dangerous` that doesn’t do anything in its +body: ``` unsafe fn dangerous() {} @@ -198,11 +234,12 @@ unsafe { } ``` -If we try to call `dangerous` without the `unsafe` block, we’ll get an error: +We must call the `dangerous` function within a separate `unsafe` block. If we +try to call `dangerous` without the `unsafe` block, we’ll get an error: ``` error[E0133]: call to unsafe function requires unsafe function or block - --> :4:5 + --> | 4 | dangerous(); | ^^^^^^^^^^^ call to unsafe function @@ -212,13 +249,19 @@ By inserting the `unsafe` block around our call to `dangerous`, we’re assertin to Rust that we’ve read the documentation for this function, we understand how to use it properly, and we’ve verified that everything is correct. +Bodies of unsafe functions are effectively `unsafe` blocks, so to perform other +unsafe operations within an unsafe function, we don’t need to add another +`unsafe` block. + #### Creating a Safe Abstraction Over Unsafe Code -As an example, let’s check out some functionality from the standard library, -`split_at_mut`, and explore how we might implement it ourselves. This safe -method is defined on mutable slices, and it takes one slice and makes it into -two by splitting the slice at the index given as an argument, as demonstrated -in Listing 19-4: +Just because a function contains unsafe code doesn’t mean the whole function +needs to be marked as unsafe. In fact, wrapping unsafe code in a safe function +is a common abstraction. As an example, let’s check out 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 into two by splitting the slice at the index given +as an argument. Using `split_at_mut` is demonstrated in Listing 19-4: ``` let mut v = vec![1, 2, 3, 4, 5, 6]; @@ -231,13 +274,12 @@ assert_eq!(a, &mut [1, 2, 3]); assert_eq!(b, &mut [4, 5, 6]); ``` -Listing 19-4: Using the safe `split_at_mut` -function +Listing 19-4: Using the safe `split_at_mut` function This function can’t be implemented using only safe Rust. An attempt might look -like Listing 19-5. For simplicity, we’re implementing `split_at_mut` as a -function rather than a method, and only for slices of `i32` values rather than -for a generic type `T`: +something like Listing 19-5, which will not compile. For simplicity, we’re +implementing `split_at_mut` as a function rather than a method, and only for +slices of `i32` values rather than for a generic type `T`. ``` fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { @@ -253,34 +295,34 @@ 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 asserts that the -index given as a parameter is within the slice by checking that the parameter -is less than or equal to the length. The assertion means that if we pass an -index that’s greater than the length of the slice to split at, the function -will panic before it attempts to use that index. +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’s +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 initial -slice to the `mid` index, and another from `mid` to the end of the slice. +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. If we try to compile this, we’ll get an error: ``` error[E0499]: cannot borrow `*slice` as mutable more than once at a time - --> :6:11 + --> | -5 | (&mut slice[..mid], +6 | (&mut slice[..mid], | ----- first mutable borrow occurs here -6 | &mut slice[mid..]) +7 | &mut slice[mid..]) | ^^^^^ second mutable borrow occurs here -7 | } +8 | } | - first borrow ends here ``` Rust’s borrow checker can’t understand that we’re borrowing different parts of the slice; it only knows that we’re borrowing from the same slice twice. -Borrowing different parts of a slice is fundamentally okay; our two `&mut -[i32]` slices aren’t overlapping. However, Rust isn’t smart enough to know -this. When we know something is okay, but Rust doesn’t, it’s time to reach for -unsafe code. +Borrowing different parts of a slice is fundamentally okay because our two +slices aren’t overlapping, but Rust isn’t smart enough to know this. When we +know something 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: @@ -304,37 +346,36 @@ 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 Chapter 4 that slices are a pointer to some data and the length of -the slice. We’ve often used the `len` method to get the length of a slice; we -can use the `as_mut_ptr` method to get access to the raw pointer of a slice. In -this case, since 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 “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`. -The assertion that the `mid` index is within the slice stays the same. Then, -the `slice::from_raw_parts_mut` function does the reverse from the `as_mut_ptr` -and `len` methods: it takes a raw pointer and a length and creates a slice. We -call `slice::from_raw_parts_mut` 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. +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. -Because slices are checked, they’re safe to use once we’ve created them. The -function `slice::from_raw_parts_mut` is an unsafe function because it takes a -raw pointer and trusts that this pointer is valid. The `offset` method on raw -pointers is also unsafe, since it trusts that the location some offset after a -raw pointer is also a valid pointer. We’ve put an `unsafe` block around our -calls to `slice::from_raw_parts_mut` and `offset` to be allowed to call them, -and we can tell by looking at the code and by adding the assertion that `mid` -must be less than or equal to `len` that all the raw pointers used within the -`unsafe` block will be valid pointers to data within the slice. This is an -acceptable and appropriate use of `unsafe`. +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 +pointers is also unsafe, because it must trust that the offset location is also +a valid pointer. We therefore had to put an `unsafe` block around our calls to +`slice::from_raw_parts_mut` and `offset` to be allowed to call them. We can +tell, by looking at the code and by adding the assertion that `mid` must be +less than or equal to `len`, that all the raw pointers used within the `unsafe` +block will be valid pointers to data within the slice. This is an acceptable +and appropriate use of `unsafe`. -Note that the resulting `split_at_mut` function is safe: we didn’t have to add -the `unsafe` keyword in front of it, and we can call this function from safe -Rust. We’ve created a safe abstraction to the unsafe code by writing an -implementation of the function that uses `unsafe` code in a safe way by only -creating valid pointers from the data this function has access to. +Note that we don’t need to mark the resulting `split_at_mut` function as +`unsafe`, and we can call this function from safe Rust. We’ve created a safe +abstraction to the unsafe code with an implementation of the function that uses +`unsafe` code in a safe way because it creates only valid pointers from the +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 @@ -355,16 +396,24 @@ Listing 19-7: Creating a slice from an arbitrary memory location We don’t own the memory at this arbitrary location, and there’s no guarantee that the slice this code creates contains valid `i32` values. Attempting to use -`slice` as if it was a valid slice would be undefined behavior. +`slice` as if it was a valid slice would result in undefined behavior. -#### `extern` Functions for Calling External Code are Unsafe +#### Using `extern` Functions to Call External Code Sometimes, your Rust code may need to interact with code written in another -language. To do this, Rust has a keyword, `extern`, that facilitates creating -and using a *Foreign Function Interface* (FFI). Listing 19-8 demonstrates how -to set up an integration with the `abs` function defined in the C standard -library. Functions declared within `extern` blocks are always unsafe to call -from Rust code: +language. For this, Rust has a keyword, `extern`, that facilitates the creation +and use of a *Foreign Function Interface* (FFI). A Foreign Function Interface +is a way for a programming language to define functions and enable a different +(foreign) 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, because 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: Filename: src/main.rs @@ -383,29 +432,34 @@ fn main() { Listing 19-8: Declaring and calling an `extern` function defined in another language -Within the `extern "C"` block, we list the names and signatures of functions -defined in a library written in another language that we want to be able to -call.`"C"` defines which *application binary interface* (ABI) the external -function uses. The ABI 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 an external function is always unsafe. If we’re calling into some other -language, that language does not enforce Rust’s safety guarantees. Since Rust -can’t check that the external code is safe, we are responsible for checking the -safety of the external code and indicating we have done so by using an `unsafe` -block to call external functions. +Within the `extern "C"` block, we list the names and signatures of external +functions from another language we want to be able to call. The `"C"` part +defines which *application binary interface* (ABI) the external function +uses---the ABI 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 -The `extern` keyword is also used for creating an interface that allows other -languages to call Rust functions. Instead of an `extern` block, we can add the -`extern` keyword and specifying the ABI to use just before the `fn` keyword. We -also add the `#[no_mangle]` annotation to tell the Rust compiler not to mangle -the name of this function. The `call_from_c` function in this example would be -accessible from C code, once we’ve compiled to a shared library and linked from -C: +You 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 from other languages, we have to disable the Rust +compiler’s name mangling. + + + + +In this example we make the `call_from_c` function accessible from C code, once +it’s compiled to a shared library and linked from C: ``` #[no_mangle] @@ -414,19 +468,19 @@ pub extern "C" fn call_from_c() { } ``` -This usage of `extern` does not require `unsafe` +This usage of `extern` does not require `unsafe`. ### Accessing or Modifying a Mutable Static Variable -We’ve gone this entire book without talking about *global variables*. Many -programming languages support them, and so does Rust. However, global variables -can be problematic: for example, if you have two threads accessing the same -mutable global variable, a data race can happen. +We’ve managed to go this entire book without talking about *global variables*, +which Rust does support, but which can be problematic with Rust’s ownership +rules. If you have two threads accessing the same mutable global variable, it +can cause a data race. -Global variables are called *static* in Rust. Listing 19-9 shows an example -declaration and use of a static variable with a string slice as a value: +Global variables are called *static* variables in Rust. Listing 19-9 shows an +example declaration and use of a static variable with a string slice as a value: Filename: src/main.rs @@ -440,22 +494,23 @@ fn main() { Listing 19-9: Defining and using an immutable static variable -`static` variables are similar to constants: their names are also in -`SCREAMING_SNAKE_CASE` by convention, and we *must* annotate the variable’s -type, which is `&'static str` in this case. Only references with the `'static` -lifetime may be stored in a static variable. Because of this, the Rust compiler -can figure out the lifetime by itself and we don’t need to annotate it -explicitly. +`static` variables are similar to constants, which we discussed in the +“Differences Between Variables and Constants†section in Chapter 3. The names +of static variables are in `SCREAMING_SNAKE_CASE` by convention, and we *must* +annotate the variable’s type, which is `&'static str` in this case. Static +variables may only store references with the `'static` lifetime, which means +the Rust compiler can figure out the lifetime by itself and we don’t need to +annotate it explicitly. Accessing an immutable static variable is safe. -Accessing immutable static variables is safe. Values in a static variable have a -fixed address in memory, and using the value will always access the same data. -Constants, on the other hand, are allowed to duplicate their data whenever they -are used. +Constants and immutable static variables may seem similar, but a subtle +difference is that values in a static variable have a fixed address in memory. +Using the value will always access the same data. Constants, on the other hand, +are allowed to duplicate their data whenever they are used. -Another way in which static variables are different from constants is that -static variables can be mutable. Both accessing and modifying mutable static -variables is unsafe. Listing 19-10 shows how to declare, access, and modify a -mutable static variable named `COUNTER`: +Another difference between constants and static variables is that static +variables can be mutable. Both accessing and modifying mutable static variables +is *unsafe*. Listing 19-10 shows how to declare, access, and modify a mutable +static variable named `COUNTER`: Filename: src/main.rs @@ -479,24 +534,25 @@ fn main() { Listing 19-10: Reading from or writing to a mutable static variable is unsafe -Just like with regular variables, we specify that a static variable should be -mutable using the `mut` keyword. Any time that we read or write from `COUNTER` -has to be within an `unsafe` block. This code compiles and prints `COUNTER: 3` -as we would expect since it’s single threaded, but having multiple threads -accessing `COUNTER` would likely result in data races. +Just like with regular variables, we specify mutability using the `mut` +keyword. Any code that reads or writes from `COUNTER` must be within an +`unsafe` block. This code compiles and prints `COUNTER: 3` as we would expect +because it’s single threaded. Having multiple threads access `COUNTER` would +likely result in data races. -Mutable data that is globally accessible is difficult to manage and ensure that -there are no data races, which is why Rust considers mutable static variables -to be unsafe. If possible, prefer using the concurrency techniques and -threadsafe smart pointers we discussed in Chapter 16 to have the compiler check +With mutable data that’s 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 +threadsafe smart pointers we discussed in Chapter 16, so the compiler checks that data accessed from different threads is done safely. ### Implementing an Unsafe Trait -Finally, the last action we’re only allowed to take when we use the `unsafe` -keyword is implementing an unsafe trait. We can declare that a trait is -`unsafe` by adding the `unsafe` keyword before `trait`, and then implementing -the trait must be marked as `unsafe` too, as shown in Listing 19-11: +Finally, the last action that only works 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`, and then implementation +of the trait must be marked as `unsafe` too, as shown in Listing 19-11: ``` unsafe trait Foo { @@ -510,42 +566,56 @@ unsafe impl Foo for i32 { Listing 19-11: Defining and implementing an unsafe trait -Like unsafe functions, methods in an unsafe trait have some invariant that the -compiler cannot verify. By using `unsafe impl`, we’re promising that we’ll -uphold these invariants. +By using `unsafe impl`, we’re promising that we’ll uphold the invariants that +the compiler can’t verify. -As an example, recall the `Sync` and `Send` marker traits from Chapter 16, and -that the compiler implements these automatically if our types are composed -entirely of `Send` and `Sync` types. If we implement a type that contains -something that’s not `Send` or `Sync` such as raw pointers, and we want to mark -our type as `Send` or `Sync`, that requires using `unsafe`. Rust can’t verify -that our type upholds the guarantees that a type can be safely sent across -threads or accessed from multiple threads, so we need to do those checks -ourselves and indicate as such with `unsafe`. +As an example, recall the `Sync` and `Send` marker traits from the “Extensible +Concurrency with the `Sync` and `Send` Traits†section of Chapter 16, and that +the compiler implements these automatically if our types are composed entirely +of `Send` and `Sync` types. If we implement a type that contains something +that’s not `Send` or `Sync`, such as raw pointers, and we want to mark that +type as `Send` or `Sync`, we must use `unsafe`. Rust can’t verify that our type +upholds the guarantees that it can be safely sent across threads or accessed +from multiple threads, so we need to do those checks ourselves and indicate as +such with `unsafe`. -Using `unsafe` to take one of these four actions isn’t wrong or frowned upon, -but it is trickier to get `unsafe` code correct since the compiler isn’t able -to help uphold memory safety. When you have a reason to use `unsafe` code, -however, it’s possible to do so, and having the explicit `unsafe` annotation -makes it easier to track down the source of problems if they occur. +### When to Use Unsafe Code + +Using `unsafe` to take one of these four actions isn’t wrong or even frowned +upon, but it is trickier to get `unsafe` code correct because the compiler isn’t +able to help uphold memory safety. When you have a reason to use `unsafe` code, +it is possible to do so, and having the explicit `unsafe` annotation makes it +easier to track down the source of problems if they occur. ## Advanced Lifetimes -Back in Chapter 10, we learned how to annotate references with lifetime -parameters to help Rust understand how the lifetimes of different references -relate. We saw how most of the time, Rust will let you elide lifetimes, but -every reference has a lifetime. There are three advanced features of lifetimes -that we haven’t covered though: *lifetime subtyping*, *lifetime bounds*, and -*trait object lifetimes*. +Back in Chapter 10 in the “Validating References with Lifetimes†section, we +learned how to annotate references with lifetime parameters to tell Rust how +lifetimes of different references relate. We saw how every reference has a +lifetime but, most of the time, Rust will let you elide lifetimes. Here we’ll +look at three advanced features of lifetimes that we haven’t covered yet: -### Lifetime Subtyping +* Lifetime subtyping, a way to ensure that one lifetime outlives another + lifetime +* Lifetime bounds, to specify a lifetime for a reference to a generic type +* Trait object lifetimes, how they’re inferred, and when they need to be + specified -Imagine that we want to write a parser. To do this, we’ll have a structure that -holds a reference to the string that we’re parsing, and we’ll call that struct -`Context`. 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. -Implementing this would look like the code in Listing 19-12, which won’t -compile because we’ve left off the lifetime annotations for now: + + + +### Lifetime Subtyping Ensures One Lifetime Outlives Another + +Lifetime subtyping is a way to specify that one lifetime should outlive another +lifetime. To explore lifetime subtyping, imagine we want to write a parser. +We’ll have 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. Implementing this would look like the code in Listing 19-12, except +this code doesn’t have the required lifetime annotations so it won’t compile: + +Filename: src/lib.rs ``` struct Context(&str); @@ -561,23 +631,44 @@ impl Parser { } ``` -Listing 19-12: Defining a `Context` struct that holds a string slice, a -`Parser` struct that holds a reference to a `Context` instance, and a `parse` -method that always returns an error referencing the string slice +Listing 19-12: Defining a parser without lifetime annotations + +Compiling the code results in errors saying that Rust expected lifetime +parameters on the string slice in `Context` and the reference to a `Context` in +`Parser`. + + + For simplicity’s sake, our `parse` function returns a `Result<(), &str>`. That -is, we don’t do anything on success, and on failure we return the part of the +is, it 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 have more -error information than that, and would actually return something created when -parsing succeeds, but we’re leaving those parts of the implementation off since -they aren’t relevant to the lifetimes part of this example. We’re also defining -`parse` to always produce an error after the first byte. Note that this may -panic if the first byte is not on a valid character boundary; again, we’re -simplifying the example in order to concentrate on the lifetimes involved. +error information than that, and would actually return something when parsing +succeeds, but we’ll leave those off because they aren’t relevant to the +lifetimes part of this example. -So how do we fill in the lifetime parameters for the string slice in `Context` -and the reference to the `Context` in `Parser`? The most straightforward thing -to do is to use the same lifetime everywhere, as shown in Listing 19-13: +To keep this code simple, we’re not going to actually write any parsing logic. +It’s very likely that somewhere in parsing logic we’d handle invalid input by +returning an error that references the part of the input that’s invalid, and +this reference is what makes the code example interesting with regards to +lifetimes. So we’re going to pretend that the logic of our parser is that the +input is invalid after the first byte. Note that this code may panic if the +first byte is not on a valid character boundary; again, we’re simplifying the +example in order to concentrate on the lifetimes involved. + + + + +To get this code compiling, 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: + +Filename: src/lib.rs ``` struct Context<'a>(&'a str); @@ -596,9 +687,21 @@ impl<'a> Parser<'a> { Listing 19-13: Annotating all references in `Context` and `Parser` with the same lifetime parameter -This compiles fine. Next, in Listing 19-14, let’s write a function that takes -an instance of `Context`, uses a `Parser` to parse that context, and returns -what `parse` returns. This won’t quite work: +This compiles fine, and tells Rust that a `Parser` holds a reference 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 said lifetime parameters were required for these references, and +we have now added lifetime parameters. + + + + +Next, in Listing 19-14, let’s add a function that takes an instance of +`Context`, uses a `Parser` to parse that context, and returns what `parse` +returns. This won’t quite work: + +Filename: src/lib.rs ``` fn parse_context(context: Context) -> Result<(), &str> { @@ -613,88 +716,93 @@ We get two quite verbose errors when we try to compile the code with the addition of the `parse_context` function: ``` -error: borrowed value does not live long enough - --> :16:5 +error[E0597]: borrowed value does not live long enough + --> src/lib.rs:14:5 | -16 | Parser { context: &context }.parse() +14 | Parser { context: &context }.parse() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough -17 | } +15 | } | - temporary value only lives until here | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the -body at 15:55... - --> :15:56 +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1... + --> src/lib.rs:13:1 | -15 | fn parse_context(context: Context) -> Result<(), &str> { - | ________________________________________________________^ -16 | | Parser { context: &context }.parse() -17 | | } +13 | / fn parse_context(context: Context) -> Result<(), &str> { +14 | | Parser { context: &context }.parse() +15 | | } | |_^ -error: `context` does not live long enough - --> :16:24 +error[E0597]: `context` does not live long enough + --> src/lib.rs:14:24 | -16 | Parser { context: &context }.parse() +14 | Parser { context: &context }.parse() | ^^^^^^^ does not live long enough -17 | } +15 | } | - borrowed value only lives until here | -note: borrowed value must be valid for the anonymous lifetime #1 defined on the -body at 15:55... - --> :15:56 +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1... + --> src/lib.rs:13:1 | -15 | fn parse_context(context: Context) -> Result<(), &str> { - | ________________________________________________________^ -16 | | Parser { context: &context }.parse() -17 | | } +13 | / fn parse_context(context: Context) -> Result<(), &str> { +14 | | Parser { context: &context }.parse() +15 | | } | |_^ ``` -These errors are saying that both the `Parser` instance we’re creating and the -`context` parameter live from the line that the `Parser` is created until the -end of the `parse_context` function, but they both need to live for the entire +These errors are saying that both the `Parser` instance that’s created and the +`context` parameter live only from when the `Parser` is created until the end +of the `parse_context` function, but they both need to live for the entire lifetime of the function. In other words, `Parser` and `context` need to *outlive* the entire function and be valid before the function starts as well as after it ends in order for all the references in this code to always be valid. Both the `Parser` we’re creating and the `context` parameter go out of scope at the end of the -function, though (since `parse_context` takes ownership of `context`). +function, though (because `parse_context` takes ownership of `context`). -Let’s look at the definitions in Listing 19-13 again, especially the signature -of the `parse` method: + + + +To figure out why we’re getting these errors, let’s look at the definitions in +Listing 19-13 again, specifically the references in the signature of the +`parse` method: ``` fn parse(&self) -> Result<(), &str> { ``` -Remember the elision rules? If we annotate the lifetimes of the references, the -signature would be: + + + +Remember the elision rules? If we annotate the lifetimes of the references +rather than eliding, the signature would be: ``` fn parse<'a>(&'a self) -> Result<(), &'a str> { ``` That is, the error part of the return value of `parse` has a lifetime that is -tied to the `Parser` instance’s lifetime (that of `&self` in the `parse` method -signature). That makes sense, as the returned string slice references the -string slice in the `Context` instance that the `Parser` holds, and we’ve -specified in the definition of the `Parser` struct that the lifetime of the -reference to `Context` that `Parser` holds and the lifetime of the string slice -that `Context` holds should be the same. +tied to the lifetime of the `Parser` instance (that of `&self` in the `parse` +method signature). That makes sense: the returned string slice references the +string slice in the `Context` instance held by the `Parser`, and the definition +of the `Parser` struct specifies that the lifetime of the reference to +`Context` and the lifetime of the string slice that `Context` holds should be +the same. The problem is that the `parse_context` function returns the value returned from `parse`, so the lifetime of the return value of `parse_context` is tied to the lifetime of the `Parser` as well. But the `Parser` instance created in the `parse_context` function won’t live past the end of the function (it’s -temporary), and the `context` will go out of scope at the end of the function +temporary), and `context` will go out of scope at the end of the function (`parse_context` takes ownership of it). -We’re not allowed to return a reference to a value that goes out of scope at -the end of the function. Rust thinks that’s what we’re trying to do because we -annotated all the lifetimes with the same lifetime parameter. That told Rust -the lifetime of the string slice that `Context` holds is the same as that of -the lifetime of the reference to `Context` that `Parser` holds. +Rust thinks we’re trying to return a reference to a value that goes out of +scope at the end of the function, because we annotated all the lifetimes with +the same lifetime parameter. That told Rust the lifetime of the 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 both `Context` and `Parser`, and that the @@ -702,7 +810,7 @@ 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 that the return value of `parse` is tied to the `Parser` is because it’s +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 @@ -710,12 +818,14 @@ 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`. -We could try only giving `Parser` and `Context` different lifetime parameters -as shown in Listing 19-15. We’ve chosen the lifetime parameter names `'s` and -`'c` here to be clearer about which lifetime goes with the string slice in -`Context` and which goes with the reference to `Context` in `Parser`. Note that -this won’t completely fix the problem, but it’s a start and we’ll look at why -this isn’t sufficient when we try to compile. +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 to +be clear about which lifetime goes with the string slice in `Context` and which +goes with the reference to `Context` in `Parser`. Note that this won’t +completely fix the problem, but it’s a start and we’ll look at why this isn’t +sufficient when we try to compile. + +Filename: src/lib.rs ``` struct Context<'s>(&'s str); @@ -744,24 +854,24 @@ whether the reference goes with the string slice or with `Context`. We’ve also added an annotation to the string slice part of the return value of `parse` to indicate that it goes with the lifetime of the string slice in `Context`. -Here’s the error we get now: +The following is the error we get now when we try to compile: ``` error[E0491]: in type `&'c Context<'s>`, reference has a longer lifetime than the data it references - --> src/main.rs:4:5 + --> src/lib.rs:4:5 | 4 | context: &'c Context<'s>, | ^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the pointer is valid for the lifetime 'c as defined on the struct at 3:0 - --> src/main.rs:3:1 +note: the pointer is valid for the lifetime 'c as defined on the struct at 3:1 + --> src/lib.rs:3:1 | 3 | / struct Parser<'c, 's> { 4 | | context: &'c Context<'s>, 5 | | } | |_^ -note: but the referenced data is only valid for the lifetime 's as defined on the struct at 3:0 - --> src/main.rs:3:1 +note: but the referenced data is only valid for the lifetime 's as defined on the struct at 3:1 + --> src/lib.rs:3:1 | 3 | / struct Parser<'c, 's> { 4 | | context: &'c Context<'s>, @@ -771,13 +881,13 @@ note: but the referenced data is only valid for the lifetime 's as defined on th Rust doesn’t know of any relationship between `'c` and `'s`. In order to be valid, the referenced data in `Context` with lifetime `'s` needs to be -constrained to guarantee that it lives longer than the reference to `Context` -that has lifetime `'c`. If `'s` is not longer than `'c`, then the reference to -`Context` might not be valid. +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. -Which gets us to the point of this section: Rust has a feature called *lifetime -subtyping*, which is a way to specify that one lifetime parameter lives at -least as long as another one. In the angle brackets where we declare lifetime +Which gets us to the point of this section: the Rust feature *lifetime +subtyping* is a way to specify 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` with the syntax `'b: 'a`. @@ -787,6 +897,8 @@ string slice) is guaranteed to live at least as long as `'c` (the lifetime of the reference to `Context`), we change the lifetime declarations to look like this: +Filename: src/lib.rs + ``` struct Parser<'c, 's: 'c> { context: &'c Context<'s>, @@ -802,16 +914,24 @@ chapter, these features are pretty niche. You won’t often need this syntax, bu it can come up in situations like this one, where you need to refer to something you have a reference to. -### Lifetime Bounds +### Lifetime Bounds on References to Generic Types -In Chapter 10, we discussed how to use trait bounds on generic types. We can -also add lifetime parameters as constraints on generic types, which are called -*lifetime bounds*. For example, consider a type that is a wrapper over -references. Recall the `RefCell` type from 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: +In the “Trait Bounds†section of Chapter 10, we discussed using trait bounds on +generic types. We can also add lifetime parameters as constraints on generic +types, and these are called *lifetime bounds*. Lifetime bounds help Rust verify +that references in generic types won’t outlive the data they’re referencing. + + + + +For an example, consider a type that is a wrapper over references. Recall the +`RefCell` type from the “`RefCell` and the Interior Mutability Pattern†+section of 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: + +Filename: src/lib.rs ``` struct Ref<'a, T>(&'a T); @@ -820,41 +940,39 @@ 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 -Without constraining the lifetime `'a` in relation to the generic parameter -`T`, we get an error because Rust doesn’t know how long the generic type `T` -will live: +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 +type `T` will live: ``` error[E0309]: the parameter type `T` may not live long enough - --> :1:19 + --> src/lib.rs:1:19 | 1 | struct Ref<'a, T>(&'a T); | ^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'a`... note: ...so that the reference type `&'a T` does not outlive the data it points at - --> :1:19 + --> src/lib.rs:1:19 | 1 | struct Ref<'a, T>(&'a T); | ^^^^^^ ``` -Since `T` can be any type, `T` could itself be a reference or a type that holds -one or more references, each of which could have their own lifetimes. Rust -can’t be sure `T` will live as long as `'a`. +Because `T` can be any type, `T` could itself be a reference or a type that +holds one or more references, each of which could have their own lifetimes. +Rust can’t be sure `T` will live as long as `'a`. -Fortunately, Rust gave us helpful advice on how to specify the lifetime bound in -this case: +Fortunately, that error gave us helpful advice on how to specify the lifetime +bound in this case: ``` consider adding an explicit lifetime bound `T: 'a` so that the reference type -`&'a T` does not outlive the data it points at. +`&'a T` does not outlive the data it points at ``` Listing 19-17 shows how to apply this advice by specifying the lifetime bound -when we declare the generic type `T`. This code now compiles because the `T: -'a` syntax specifies that `T` can be any type, but if it contains any -references, the references must live at least as long as `'a`: +when we declare the generic type `T`. ``` struct Ref<'a, T: 'a>(&'a T); @@ -863,7 +981,11 @@ struct Ref<'a, T: 'a>(&'a T); Listing 19-17: Adding lifetime bounds on `T` to specify that any references in `T` live at least as long as `'a` -We could choose to solve this in a different way, shown in the definition of a +This code now compiles because the `T: 'a` syntax specifies that `T` can be any +type, but if it contains any references, the references must live at least as +long as `'a`. + +We could solve this in a different way, 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: @@ -875,80 +997,92 @@ struct StaticRef(&'static T); Listing 19-18: Adding a `'static` lifetime bound to `T` to constrain `T` to types that have only `'static` references or no references -Types without any references count as `T: 'static`. Because `'static` means the -reference must live as long as the entire program, a type that contains no -references meets the criteria of all references living as long as the entire -program (since there are no references). Think of it this way: if the borrow -checker is concerned about references living long enough, then there’s no real +Because `'static` means the reference must live as long as the entire program, +a type that contains no references meets the criteria of all references living +as long as the entire program (because there are no references). For the borrow +checker concerned about references living long enough, there’s no real distinction between a type that has no references and a type that has references that live forever; both of them are the same for the purpose of determining whether or not a reference has a shorter lifetime than what it refers to. -### Trait Object Lifetimes +### Inference of Trait Object Lifetimes -In Chapter 17, we learned about trait objects that consist of putting a trait -behind a reference in order to use dynamic dispatch. However, we didn’t discuss -what happens if the type implementing the trait used in the trait object has a -lifetime. Consider Listing 19-19, where we have a trait `Foo` and a struct -`Bar` that holds a reference (and thus has a lifetime parameter) that -implements trait `Foo`, and we want to use an instance of `Bar` as the trait -object `Box`: +In Chapter 17 in the “Using Trait Objects that Allow for Values of Different +Types†section, we discussed trait objects, consisting of a trait behind a +reference, that allow us to use dynamic dispatch. We haven’t yet discussed what +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`. `Ball` 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`: + +Filename: src/main.rs ``` -trait Foo { } +trait Red { } -struct Bar<'a> { - x: &'a i32, +struct Ball<'a> { + diameter: &'a i32, } -impl<'a> Foo for Bar<'a> { } +impl<'a> Red for Ball<'a> { } -let num = 5; +fn main() { + let num = 5; -let obj = Box::new(Bar { x: &num }) as Box; + let obj = Box::new(Ball { diameter: &num }) as Box; +} ``` Listing 19-19: Using a type that has a lifetime parameter with a trait object This code compiles without any errors, even though we haven’t said anything -about the lifetimes involved in `obj`. This works because there are rules -having to do with lifetimes and trait objects: +explicit about the lifetimes involved in `obj`. This works because there are +rules having to do with lifetimes and trait objects: * The default lifetime of a trait object is `'static`. -* If we have `&'a X` or `&'a mut X`, then the default is `'a`. -* If we have a single `T: 'a` clause, then the default is `'a`. -* If we have multiple `T: 'a`-like clauses, then there is no default; we must +* With `&'a Trait` or `&'a mut Trait`, the default lifetime is `'a`. +* With a single `T: 'a` clause, the default lifetime is `'a`. +* With multiple `T: 'a`-like clauses, there is no default; we must be explicit. When we must be explicit, we can add a lifetime bound on a trait object like -`Box` with the syntax `Box` or `Box`, depending +`Box` with the syntax `Box` or `Box`, depending on what’s needed. Just as with the other bounds, this means that any -implementer of the `Foo` trait that has any references inside must have the -lifetime specified in the trait object bounds as those references. +implementor of the `Red` trait that has references inside must have the +same lifetime specified in the trait object bounds as those references. Next, let’s take a look at some other advanced features dealing with traits! ## Advanced Traits -We covered traits in Chapter 10, but like lifetimes, we didn’t get to all the +We first covered traits in the “Traits: Defining Shared Behavior†section of +Chapter 10 but, like lifetimes, we didn’t get to some of the more advanced details. Now that we know more Rust, we can get into the nitty-gritty. -### Associated Types +### Associated Types Specify Placeholder Types in Trait Definitions *Associated types* are a way of associating a type placeholder with a trait such that the trait method definitions can use these placeholder types in their -signatures. The implementer of a trait will specify the concrete type to be -used in this type’s place for the particular implementation. +signatures. The implementor of a trait will specify the concrete type to be +used in this type’s place for the particular implementation. That way, we can +define a trait that uses some types without needing to know exactly what those +types are until the trait is implemented. -We’ve described most of the things in this chapter as being very rare. -Associated types are somewhere in the middle; they’re more rare than the rest -of the book, but more common than many of the things in this chapter. + + -An example of a trait with an associated type is the `Iterator` trait provided -by the standard library. It has an associated type named `Item` that stands in -for the type of the values that we’re iterating over. We mentioned in Chapter -13 that the definition of the `Iterator` trait is as shown in Listing 19-20: +We’ve described most of the things in this chapter as being needed very rarely. +Associated types are somewhere in the middle; they’re used more rarely than the +rest of the book, but more commonly than many of the things in this chapter. + +One example of a trait with an associated type is the `Iterator` trait provided +by the standard library. This has an associated type named `Item` that stands +in for the type of the values it’s 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: ``` pub trait Iterator { @@ -960,26 +1094,33 @@ pub trait Iterator { Listing 19-20: The definition of the `Iterator` trait that has an associated type `Item` -This says that the `Iterator` trait has an associated type named `Item`. `Item` -is a placeholder type, and the return value of the `next` method will return -values of type `Option`. Implementers of this trait will specify -the concrete type for `Item`, and the `next` method will return an `Option` -containing a value of whatever type the implementer has specified. +The `Iterator` trait has an associated type named `Item`. This is a placeholder +type, and the `next` method will return values of type `Option`. +Implementors of this 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 Versus Generics -When we implemented the `Iterator` trait on the `Counter` struct in Listing -13-6, we specified that the `Item` type was `u32`: +This may seem like a similar concept to generics, in that it allows us to +define a function without specifying what types it can deal with. So why use +associated types? + +Let’s examine the difference with an example that implements the `Iterator` +trait on the `Counter` struct from Chapter 13. In Listing 13-21, we specified +that the `Item` type was `u32`: + +Filename: src/lib.rs ``` impl Iterator for Counter { type Item = u32; fn next(&mut self) -> Option { + // --snip-- ``` -This feels similar to generics. So why isn’t the `Iterator` trait defined as -shown in Listing 19-21? +This feels similar to generics. So why not just define the `Iterator` trait +with generics as shown in Listing 19-21? ``` pub trait Iterator { @@ -989,133 +1130,43 @@ pub trait Iterator { Listing 19-21: A hypothetical definition of the `Iterator` trait using generics -The difference is that with the definition in Listing 19-21, we could also -implement `Iterator for Counter`, or any other type as well, so that -we’d have multiple implementations of `Iterator` for `Counter`. In other words, -when a trait has a generic parameter, we can implement that trait for a type -multiple times, changing the generic type parameters’ concrete types each time. -Then when we use the `next` method on `Counter`, we’d have to provide type +The difference lies in the fact that when using generics like in Listing 19-21, +we have to annotate the types in each implementation. This is because 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’d then have to provide type annotations to indicate which implementation of `Iterator` we wanted to use. -With associated types, we can’t implement a trait on a type multiple times. -Using the actual definition of `Iterator` from Listing 19-20, we can only -choose once what the type of `Item` will be, since there can only be one `impl +With associated types, we don’t need to annotate types because we can’t +implement a trait on a type multiple times. With Listing 19-20, we can only +choose once what the type of `Item` will be, because there can only be one `impl Iterator for Counter`. We don’t have to specify that we want an iterator of `u32` values everywhere that we call `next` on `Counter`. -The benefit of not having to specify generic type parameters when a trait uses -associated types shows up in another way as well. Consider the two traits -defined in Listing 19-22. Both are defining a trait having to do with a graph -structure that contains nodes of some type and edges of some type. `GGraph` is -defined using generics, and `AGraph` is defined using associated types: +### Default Generic Type Parameters and Operator Overloading -``` -trait GGraph { - // methods would go here -} +When we use generic type parameters, we can specify a default concrete type for +the generic type. This eliminates the need for implementors of the trait to +specify a concrete type if the default type works. The syntax for specifying a +default type for a generic type is to put `` when +declaring the generic type. -trait AGraph { - type Node; - type Edge; +A great example of a situation where this is useful is with operator +overloading. Operator overloading is customizing the behavior of an operator +(like `+`) in particular situations. - // methods would go here -} -``` - -Listing 19-22: Two graph trait definitions, `GGraph` using generics and -`AGraph` using associated types for `Node` and `Edge` - -Let’s say we wanted to implement a function that computes the distance between -two nodes in any types that implement the graph trait. With the `GGraph` trait -defined using generics, our `distance` function signature would have to look -like Listing 19-23: - -``` -fn distance>(graph: &G, start: &N, end: &N) -> u32 { - // --snip-- -} -``` - -Listing 19-23: The signature of a `distance` function that uses the trait -`GGraph` and has to specify all the generic parameters - -Our function would need to specify the generic type parameters `N`, `E`, and -`G`, where `G` is bound by the trait `GGraph` that has type `N` as its `Node` -type and type `E` as its `Edge` type. Even though `distance` doesn’t need to -know the types of the edges, we’re forced to declare an `E` parameter, because -we need to to use the `GGraph` trait and that requires specifying the type for -`Edge`. - -Contrast with the definition of `distance` in Listing 19-24 that uses the -`AGraph` trait from Listing 19-22 with associated types: - -``` -fn distance(graph: &G, start: &G::Node, end: &G::Node) -> u32 { - // --snip-- -} -``` - -Listing 19-24: The signature of a `distance` function that uses the trait -`AGraph` and the associated type `Node` - -This is much cleaner. We only need to have one generic type parameter, `G`, -with the trait bound `AGraph`. Since `distance` doesn’t use the `Edge` type at -all, it doesn’t need to be specified anywhere. To use the `Node` type -associated with `AGraph`, we can specify `G::Node`. - -#### Trait Objects with Associated Types - -You may have been wondering why we didn’t use a trait object in the `distance` -functions in Listing 19-23 and Listing 19-24. The signature for the `distance` -function using the generic `GGraph` trait does get a bit more concise using a -trait object: - -``` -fn distance(graph: &GGraph, start: &N, end: &N) -> u32 { - // --snip-- -} -``` - -This might be a more fair comparison to Listing 19-24. Specifying the `Edge` -type is still required, though, which means Listing 19-24 is still preferable -since we don’t have to specify something we don’t use. - -It’s not possible to change Listing 19-24 to use a trait object for the graph, -since then there would be no way to refer to the `AGraph` trait’s associated -type. - -It is possible in general to use trait objects of traits that have associated -types, though; Listing 19-25 shows a function named `traverse` that doesn’t -need to use the trait’s associated types in other arguments. We do, however, -have to specify the concrete types for the associated types in this case. Here, -we’ve chosen to accept types that implement the `AGraph` trait with the -concrete type of `usize` as their `Node` type and a tuple of two `usize` values -for their `Edge` type: - -``` -fn traverse(graph: &AGraph) { - // --snip-- -} -``` - -While trait objects mean that we don’t need to know the concrete type of the -`graph` parameter at compile time, we do need to constrain the use of the -`AGraph` trait in the `traverse` function by the concrete types of the -associated types. If we didn’t provide this constraint, Rust wouldn’t be able -to figure out which `impl` to match this trait object to. - -### Operator Overloading and Default Type Parameters - -The `` syntax is used in another way as well: to -specify the default type for a generic type. A great example of a situation -where this is useful is operator overloading. + + Rust does not allow you to create your own operators or overload arbitrary -operators, but the operations and corresponding traits listed in `std::ops` can -be overloaded by implementing the traits associated with the operator. For -example, Listing 19-25 shows how to overload the `+` operator by implementing -the `Add` trait on a `Point` struct so that we can add two `Point` instances -together: +operators, but you *can* overload the operations and corresponding traits +listed in `std::ops` by implementing the traits associated with the operator. +For example, in Listing 19-22 we overload the `+` operator to add two `Point` +instances together. We do this by implementing the `Add` trait on a `Point` +struct: Filename: src/main.rs @@ -1145,15 +1196,15 @@ fn main() { } ``` -Listing 19-25: Implementing the `Add` trait to overload the `+` operator for +Listing 19-22: Implementing the `Add` trait to overload the `+` operator for `Point` instances -We’ve implemented the `add` method to add the `x` values of two `Point` -instances together and the `y` values of two `Point` instances together to -create a new `Point`. The `Add` trait has an associated type named `Output` -that’s used to determine the type returned from the `add` method. +The `add` method adds the `x` values of two `Point` instances together and the +`y` values of two `Point` instances together to create a new `Point`. The `Add` +trait has an associated type named `Output` that determines the type returned +from the `add` method. -Let’s look at the `Add` trait in a bit more detail. Here’s its definition: +The default generic type here is within the `Add` trait. Here’s its definition: ``` trait Add { @@ -1163,18 +1214,29 @@ trait Add { } ``` -This should look familiar; it’s a trait with one method and an associated type. -The new part is the `RHS=Self` in the angle brackets: this syntax is called -*default type parameters*. `RHS` is a generic type parameter (short for “right -hand sideâ€) that’s used for 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 the type of `Self` (the type -that we’re implementing `Add` on). +This should look generally familiar, as a trait with one method and an +associated type. The new part here is the `RHS=Self` in the angle brackets: +this syntax is called *default type parameters*. The `RHS` generic type +parameter---short for “right hand sideâ€---that’s used to define 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. -Let’s look at another example of implementing the `Add` trait. Imagine we have -two structs holding values in different units, `Millimeters` and `Meters`. We -can implement `Add` for `Millimeters` in different ways as shown in Listing -19-26: + + + +When we implemented `Add` for `Point`, we made use of the default for `RHS` +because we wanted to add two `Point` instances together. 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 be able 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 right hand side as shown +in Listing 19-23: + +Filename: src/lib.rs ``` use std::ops::Add; @@ -1182,14 +1244,6 @@ use std::ops::Add; struct Millimeters(u32); struct Meters(u32); -impl Add for Millimeters { - type Output = Millimeters; - - fn add(self, other: Millimeters) -> Millimeters { - Millimeters(self.0 + other.0) - } -} - impl Add for Millimeters { type Output = Millimeters; @@ -1199,147 +1253,268 @@ impl Add for Millimeters { } ``` -Listing 19-26: Implementing the `Add` trait on `Millimeters` to be able to add -`Millimeters` to `Millimeters` and `Millimeters` to `Meters` +Listing 19-23: Implementing the `Add` trait on `Millimeters` to be able to add +`Millimeters` to `Meters` -If we’re adding `Millimeters` to other `Millimeters`, we don’t need to -parameterize the `RHS` type for `Add` since the default `Self` type is what we -want. If we want to implement adding `Millimeters` and `Meters`, then we need -to say `impl Add` to set the value of the `RHS` type parameter. +To be able 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`. Default type parameters are used in two main ways: 1. To extend a type without breaking existing code. -2. To allow customization in a way most users don’t want. +2. To allow customization in specific cases most users won’t need. -The `Add` trait is an example of the second purpose: most of the time, you’re -adding two like types together. Using a default type parameter in the `Add` -trait definition makes it easier to implement the trait since you don’t have to -specify the extra parameter most of the time. In other words, we’ve removed a -little bit of implementation boilerplate. + + -The first purpose is similar, but in reverse: since existing implementations of -a trait won’t have specified a type parameter, if we want to add a type -parameter to an existing trait, giving it a default will let us extend the +The standard library’s `Add` trait is an example of the second purpose: most of +the time, you’re adding two like types together, but it gives the ability for +customizing 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 little bit of implementation boilerplate isn’t needed, +making it easier to use the trait. + +The first purpose is similar, 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. -### Fully Qualified Syntax for Disambiguation +### Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name -Rust cannot prevent a trait from having a method with the same name as another -trait’s method, nor can it prevent us from implementing both of these traits on -one type. We can also have a method implemented directly on the type with the -same name as well! In order to be able to call each of the methods with the -same name, then, we need to tell Rust which one we want to use. Consider the -code in Listing 19-27 where traits `Foo` and `Bar` both have method `f` and we -implement both traits on struct `Baz`, which also has a method named `f`: +Nothing in Rust prevents a trait from having a method with the same name as +another trait’s method, nor can it prevent us from implementing both of these +traits on one type. It’s also possible to have a method implemented directly on +the type with the same name as methods from traits as well! + + + + +When calling methods with the same name, then, we need to tell Rust which one +we 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 itself already has a method named +`fly` implemented on it. Each `fly` method does something different: Filename: src/main.rs ``` -trait Foo { - fn f(&self); +trait Pilot { + fn fly(&self); } -trait Bar { - fn f(&self); +trait Wizard { + fn fly(&self); } -struct Baz; +struct Human; -impl Foo for Baz { - fn f(&self) { println!("Baz’s impl of Foo"); } +impl Pilot for Human { + fn fly(&self) { + println!("This is your captain speaking."); + } } -impl Bar for Baz { - fn f(&self) { println!("Baz’s impl of Bar"); } +impl Wizard for Human { + fn fly(&self) { + println!("Up!"); + } } -impl Baz { - fn f(&self) { println!("Baz's impl"); } -} - -fn main() { - let b = Baz; - b.f(); +impl Human { + fn fly(&self) { + println!("*waving arms furiously*"); + } } ``` -Listing 19-27: Implementing two traits that both have a method with the same -name as a method defined on the struct directly +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 -For the implementation of the `f` method for the `Foo` trait on `Baz`, we’re -printing out `Baz's impl of Foo`. For the implementation of the `f` method for -the `Bar` trait on `Baz`, we’re printing out `Baz's impl of Bar`. The -implementation of `f` directly on `Baz` prints out `Baz's impl`. What should -happen when we call `b.f()`? In this case, Rust will always use the -implementation on `Baz` directly and will print out `Baz's impl`. - -In order to be able to call the `f` method from `Foo` and the `f` method from -`Baz` rather than the implementation of `f` directly on `Baz`, we need to use -the *fully qualified syntax* for calling methods. It works like this: for any -method call like: - -``` -receiver.method(args); -``` - -We can fully qualify the method call like this: - -``` -::method(receiver, args); -``` - -So in order to disambiguate and be able to call all the `f` methods defined in -Listing 19-27, we specify that we want to treat the type `Baz` as each trait -within angle brackets, then use two colons, then call the `f` method and pass -the instance of `Baz` as the first argument. Listing 19-28 shows how to call -`f` from `Foo` and then `f` from `Bar` on `b`: +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: Filename: src/main.rs ``` fn main() { - let b = Baz; - b.f(); - ::f(&b); - ::f(&b); + let person = Human; + person.fly(); } ``` -Listing 19-28: Using fully qualified syntax to call the `f` methods defined as -part of the `Foo` and `Bar` traits +Listing 19-25: Calling `fly` on an instance of `Human` -This will print: +Running this will print out `*waving arms furiously*`, which shows that Rust +called the `fly` method implemented on `Human` directly. + +In order to call the `fly` methods from either the `Pilot` trait or the +`Wizard` trait, we need to use more explicit syntax in order to specify which +`fly` method we mean. This syntax is demonstrated in Listing 19-26: + +Filename: src/main.rs ``` -Baz's impl -Baz’s impl of Foo -Baz’s impl of Bar +fn main() { + let person = Human; + Pilot::fly(&person); + Wizard::fly(&person); + person.fly(); +} ``` -We only need the `Type as` part if it’s ambiguous, and we only need the `<>` -part if we need the `Type as` part. So if we only had the `f` method directly -on `Baz` and the `Foo` trait implemented on `Baz` in scope, we could call the -`f` method in `Foo` by using `Foo::f(&b)` since we wouldn’t have to -disambiguate from the `Bar` trait. +Listing 19-26: Specifying which trait’s `fly` method we want to call -We could also have called the `f` defined directly on `Baz` by using -`Baz::f(&b)`, but since that definition of `f` is the one that gets used by -default when we call `b.f()`, it’s not required to fully specify that -implementation if that’s what we 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 choose to write +`Human::fly(&person)`, which is equivalent to `person.fly()` that we had in +Listing 19-26, but is a bit longer to write if we don’t need to disambiguate. -### Supertraits to Use One Trait’s Functionality Within Another Trait +Running this code will print: -Sometimes, we may want a trait to be able to rely on another trait also being -implemented wherever our trait is implemented, so that our trait can use the -other trait’s functionality. The required trait is a *supertrait* of the trait -we’re implementing. +``` +This is your captain speaking. +Up! +*waving arms furiously* +``` + +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`. + +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 +example, take the `Animal` trait in Listing 19-27 that has the associated +function `baby_name`, the implementation of `Animal` for the struct `Dog`, and +the associated function `baby_name` defined on `Dog` directly: + +Filename: src/main.rs + +``` +trait Animal { + fn baby_name() -> String; +} + +struct Dog; + +impl Dog { + fn baby_name() -> String { + String::from("Spot") + } +} + +impl Animal for Dog { + fn baby_name() -> String { + String::from("puppy") + } +} + +fn main() { + println!("A baby dog is called a {}", Dog::baby_name()); +} +``` + +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 + +This code is for an animal shelter where they want to give all puppies the name +Spot, which is implemented in the `baby_name` associated function that is +defined on `Dog`. The `Dog` type also implements the trait `Animal`, which +describes characteristics that all animals have. Baby dogs are called puppies, +and that is expressed in the implementation of the `Animal` trait on `Dog` in +the `baby_name` function associated with the `Animal` trait. + +In `main`, we’re calling the `Dog::baby_name` function, which calls the +associated function defined on `Dog` directly. This code prints: + +``` +A baby dog is called a Spot +``` + +This isn’t what we wanted. We want to call the `baby_name` function that’s part +of the `Animal` trait that we implemented on `Dog` so that we print `A baby dog +is called a puppy`. The technique we used in Listing 19-26 doesn’t help here; +if we change `main` to be the code in Listing 19-28, we’ll get a compilation +error: + +Filename: src/main.rs + +``` +fn main() { + println!("A baby dog is called a {}", Animal::baby_name()); +} +``` + +Listing 19-28: Attempting to call the `baby_name` function from the `Animal` +trait, but Rust doesn’t know which implementation to use + +Because `Animal::baby_name` is an associated function rather than a method, and +thus doesn’t have a `self` parameter, Rust has no way to figure out which +implementation of `Animal::baby_name` we want. We’ll get this compiler error: + +``` +error[E0283]: type annotations required: cannot resolve `_: Animal` + --> src/main.rs:20:43 + | +20 | println!("A baby dog is called a {}", Animal::baby_name()); + | ^^^^^^^^^^^^^^^^^ + | + = note: required by `Animal::baby_name` +``` + +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: + +Filename: src/main.rs + +``` +fn main() { + println!("A baby dog is called a {}", ::baby_name()); +} +``` + +Listing 19-29: Using fully qualified syntax to specify that we want to call the +`baby_name` function from the `Animal` trait as implemented on `Dog` + +We’re providing Rust with a type annotation within the angle brackets, and +we’re specifying that we want to call the `baby_name` method from the `Animal` +trait as implemented on `Dog` by saying that we want to treat the `Dog` type as +an `Animal` for this function call. This code will now print what we want: + +``` +A baby dog is called a puppy +``` + +In general, fully qualified syntax is defined as: + +``` +::function(receiver_if_method, next_arg, ...); +``` + +For associated functions, there would not be a `receiver`, there would only be +the list of other arguments. We could choose to use fully qualified syntax +everywhere that we call functions or methods. However, we’re allowed to leave +out any part of this syntax that Rust is able to figure out from other +information in the program. We only need to use this more verbose syntax in +cases where there are multiple implementations that use the same name and Rust +needs help in order to know which implementation we want to call. + +### Using Supertraits to Require One Trait’s Functionality Within Another Trait + +Sometimes, we may need one trait to use another trait’s functionality. In this +case, we need to be able to rely on the dependent trait also being implemented. +The trait we’re relying on is a *supertrait* of the trait we’re implementing. For example, let’s say we want to make an `OutlinePrint` trait with an -`outline_print` method that will print out a value outlined in asterisks. That -is, if our `Point` struct implements `Display` to result in `(x, y)`, calling -`outline_print` on a `Point` instance that has 1 for `x` and 3 for `y` would -look like: +`outline_print` method that will print out a value framed in asterisks. That +is, given a `Point` struct that implements `Display` to result in `(x, y)`, +when we call `outline_print` on a `Point` instance that has 1 for `x` and 3 for +`y`, it should print the following: ``` ********** @@ -1349,13 +1524,14 @@ look like: ********** ``` -In the implementation of `outline_print`, since we want to be able to use the -`Display` trait’s functionality, we need to be able to say that the -`OutlinePrint` trait will only work 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`. It’s like adding a -trait bound to the trait. Listing 19-29 shows an implementation of the -`OutlinePrint` trait: +In the implementation of `outline_print`, we want to use the `Display` trait’s +functionality. We therefore need to specify that the `OutlinePrint` trait will +only work for types that also implement `Display` and therefore provide the +functionality that `OutlinePrint` needs. We can do that in the trait definition +by specifying `OutlinePrint: Display`. This is similar to adding a trait bound +to the trait. Listing 19-30 shows an implementation of the `OutlinePrint` trait: + +Filename: src/main.rs ``` use std::fmt; @@ -1373,18 +1549,19 @@ trait OutlinePrint: fmt::Display { } ``` -Listing 19-29: Implementing the `OutlinePrint` trait that requires the +Listing 19-30: Implementing the `OutlinePrint` trait that requires the functionality from `Display` Because we’ve specified that `OutlinePrint` requires the `Display` trait, we -can use `to_string` in `outline_print` (`to_string` is automatically -implemented for any type that implements `Display`). If we hadn’t added the `: -Display` after the trait name and we tried to use `to_string` in -`outline_print`, we’d get an error that no method named `to_string` was found -for the type `&Self` in the current scope. +can use the `to_string` function that’s 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. -If we try to implement `OutlinePrint` on a type that doesn’t implement -`Display`, such as the `Point` struct: +Let’s see what happens if we try to implement `OutlinePrint` on a type that +doesn’t implement `Display`, such as the `Point` struct: + +Filename: src/main.rs ``` struct Point { @@ -1395,25 +1572,24 @@ struct Point { impl OutlinePrint for Point {} ``` -We’ll get an error that `Display` isn’t implemented and that `Display` is -required by `OutlinePrint`: +We’ll get an error saying that `Display` is required but not implemented: ``` error[E0277]: the trait bound `Point: std::fmt::Display` is not satisfied --> src/main.rs:20:6 | 20 | impl OutlinePrint for Point {} - | ^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for - `Point` + | ^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter; + try using `:?` instead if you are using a format string | - = note: `Point` cannot be formatted with the default formatter; try using - `:?` instead if you are using a format string - = note: required by `OutlinePrint` + = help: the trait `std::fmt::Display` is not implemented for `Point` ``` Once we implement `Display` on `Point` and satisfy the constraint that `OutlinePrint` requires, like so: +Filename: src/main.rs + ``` use std::fmt; @@ -1430,19 +1606,23 @@ outline of asterisks. ### The Newtype Pattern to Implement External Traits on External Types -In Chapter 10, we mentioned the orphan rule, which says we’re allowed to -implement a trait on a type as long as either the trait or the type are local -to our crate. One way to get around this restriction is to use the *newtype -pattern*, which involves creating a new type using a tuple struct with one -field as 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 originating from the Haskell programming language. -There’s no runtime performance penalty for using this pattern. The wrapper type -is elided at compile time. +In Chapter 10 in the “Implementing a Trait on a Type†section, we mentioned the +orphan rule that says 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 is 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 will 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 originating from +the Haskell programming language. There’s no runtime performance penalty for +using this pattern, and the wrapper type is elided at compile time. -For example, if we wanted to implement `Display` on `Vec`, 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-30: +As an example, 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 both defined outside of 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 @@ -1463,21 +1643,30 @@ fn main() { } ``` -Listing 19-30: Creating a `Wrapper` type around `Vec` to be able to +Listing 19-31: Creating a `Wrapper` type around `Vec` to be able to implement `Display` -The implementation of `Display` uses `self.0` to access the inner `Vec`, and -then we can use the functionality of the `Display` type on `Wrapper`. +The implementation of `Display` uses `self.0` to access the inner `Vec`, +because `Wrapper` is a tuple struct and the `Vec` is the item at index 0 in the +tuple. Then we can use the functionality of the `Display` type on `Wrapper`. -The downside is that since `Wrapper` is a new type, it doesn’t have the methods -of the value it’s holding; we’d have to implement all the methods of `Vec` like -`push`, `pop`, and all the rest directly on `Wrapper` to delegate to `self.0` -in order to be able to treat `Wrapper` exactly like a `Vec`. If we wanted the -new type to have every single method that the inner type has, implementing the -`Deref` trait that we discussed in Chapter 15 on the wrapper to return the -inner type can 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’d have to implement just the methods we do want ourselves. + + + +The downside of this method is that, because `Wrapper` is a new type, it +doesn’t have the methods of the value it’s holding; we’d have to implement all +the methods of `Vec` directly on `Wrapper`, so that it can delegate to +`self.0`--- this allows us to treat `Wrapper` exactly like a `Vec`. If we +wanted the new type to have every single method that 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 can 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’d have to implement just the +methods we do want ourselves. That’s how the newtype pattern is used in relation to traits; it’s also a useful pattern without having traits involved. Let’s switch focus now to talk @@ -1485,49 +1674,51 @@ about some advanced ways to interact with Rust’s type system. ## Advanced Types -The Rust type system has some features that we’ve mentioned or used without -discussing. We started talking about the newtype pattern in regards to traits; -we’ll start with a more general discussion about why newtypes are useful as -types. We’ll then move to type aliases, a feature that is similar to newtypes -but has slightly different semantics. We’ll also discuss the `!` type and -dynamically sized types. +The Rust type system has some features that we’ve mentioned in this book but +haven’t yet discussed. We’ll start our discussion on advanced types with a more +general discussion about why newtypes are useful as types. We’ll then move to +type aliases, a feature similar to newtypes but with slightly different +semantics. We’ll also discuss the `!` type and dynamically sized types. ### Using the Newtype Pattern for Type Safety and Abstraction -The newtype pattern that we started discussing at the end of the “Advanced -Traits†section, where we create a new type as a tuple struct with one field -that wraps a type can also be useful for statically enforcing that values are -never confused, and is often used to indicate the units of a value. We actually -had an example of this in Listing 19-26: the `Millimeters` and `Meters` structs -both wrap `u32` values in a new type. If we write a function with a parameter -of type `Millimeters`, we won’t be able to compile a program that accidentally -tries to call that function with a value of type `Meters` or a plain `u32`. +> This section assumes you’ve read the newtype pattern section in the “Advanced +> Traits†section. -Another reason to use the newtype pattern is to abstract away some -implementation details of a type: the wrapper type can expose a different -public API than the private inner type would if we used it directly in order to -restrict the functionality that is available, for example. New types can also -hide internal generic types. For example, we could provide a `People` type that -wraps a `HashMap` that stores a person’s ID associated with their -name. Code using `People` would only interact with the public API we provide, -such as a method to add a name string to the `People` collection, and that code -wouldn’t need to know that we assign an `i32` ID to names internally. The -newtype pattern is a lightweight way to achieve encapsulation to hide -implementation details that we discussed in Chapter 17. +The newtype pattern is useful for other things beyond what we’ve discussed so +far, including statically enforcing that values are never confused, and as +indication of the units of a value. We actually had an example of this in +Listing 19-23: the `Millimeters` and `Meters` structs both wrap `u32` values in +a newtype. If we write a function with a parameter of type `Millimeters`, we +won’t be able to compile a program that accidentally tries to call that +function with a value of type `Meters` or a plain `u32`. + +Another use is in abstracting away some implementation details of a type: the +wrapper type can expose a public API that’s different to the API of the private +inner type, if we used it directly to restrict the available functionality, for +example. + +Newtypes can also hide internal generic types. For example, we could provide a +`People` type to wrap a `HashMap` that stores a person’s ID +associated with their name. Code using `People` would only interact with the +public API we provide, such as a method to add a name string to the `People` +collection, and that code wouldn’t need to know that we assign an `i32` ID to +names internally. The newtype pattern is a lightweight way to achieve +encapsulation to hide implementation details that we discussed in the +“Encapsulation that Hides Implementation Details†section of Chapter 17. ### Type Aliases Create Type Synonyms -The newtype pattern involves creating a new struct to be a new, separate type. -Rust also provides the ability to declare a *type alias* with the `type` -keyword to give an existing type another name. For example, we can create the -alias `Kilometers` to `i32` like so: +Alongside 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` +keyword. For example, we can create the alias `Kilometers` to `i32` like so: ``` type Kilometers = i32; ``` This means `Kilometers` is a *synonym* for `i32`; unlike the `Millimeters` and -`Meters` types we created in Listing 19-26, `Kilometers` is not a separate, new +`Meters` types we created in Listing 19-23, `Kilometers` is not a separate, new type. Values that have the type `Kilometers` will be treated exactly the same as values of type `i32`: @@ -1540,11 +1731,10 @@ let y: Kilometers = 5; println!("x + y = {}", x + y); ``` -Since `Kilometers` is an alias for `i32`, they’re the same type. We can add -values of type `i32` and `Kilometers` together, and we can pass `Kilometers` -values to functions that take `i32` parameters. We don’t get the type checking -benefits that we get from the newtype pattern that we discussed in the previous -section. +Because `Kilometers` and `i32`, are the same type, we can add values of both +types, and we can also pass `Kilometers` values to functions that take `i32` +parameters. With this method, though, we don’t get the type checking benefits +that we get from the newtype pattern discussed in the previous section. The main use case for type synonyms is to reduce repetition. For example, we may have a lengthy type like this: @@ -1555,7 +1745,7 @@ Box Writing this out in function signatures and as type annotations all over the place can be tiresome and error-prone. Imagine having a project full of code -like that in Listing 19-31: +like that in Listing 19-32: ``` let f: Box = Box::new(|| println!("hi")); @@ -1569,12 +1759,11 @@ fn returns_long_type() -> Box { } ``` -Listing 19-31: Using a long type in many places +Listing 19-32: Using a long type in many places -A type alias makes this code more manageable by reducing the amount of -repetition this project has. Here, we’ve introduced an alias named `Thunk` for -the verbose type, and we can replace all uses of the type with the shorter -`Thunk` as shown in Listing 19-32: +A type alias makes this code more manageable by reducing the repetition. Here, +we’ve introduced an alias named `Thunk` for the verbose type, and can replace +all uses of the type with the shorter `Thunk` as shown in Listing 19-33: ``` type Thunk = Box; @@ -1590,18 +1779,19 @@ fn returns_long_type() -> Thunk { } ``` -Listing 19-32: Introducing a type alias `Thunk` to reduce repetition +Listing 19-33: Introducing a type alias `Thunk` to reduce repetition Much easier to read and write! Choosing a good name for a type alias can help communicate your intent as well (*thunk* is a word for code to be evaluated at a later time, so it’s an appropriate name for a closure that gets stored). -Another common use of type aliases is with the `Result` type. Consider -the `std::io` module in the standard library. I/O operations often return a -`Result`, since their operations may fail to work. There’s a -`std::io::Error` struct that represents all of the possible I/O errors. Many of -the functions in `std::io` will be returning `Result` where the `E` is -`std::io::Error`, such as these functions in the `Write` trait: +Type aliases are also commonly used with the `Result` type for reducing +repetition. Consider the `std::io` module in the standard library. I/O +operations often return a `Result` to handle situations when operations +fail to work. This library has a `std::io::Error` struct that represents all +possible I/O errors. Many of the functions in `std::io` will be returning +`Result` where the `E` is `std::io::Error`, such as these functions in +the `Write` trait: ``` use std::io::Error; @@ -1616,16 +1806,16 @@ pub trait Write { } ``` -We’re writing `Result<..., Error>` a lot. As such, `std::io` has this type +We have `Result<..., Error>` repeated a lot. As such, `std::io` has this type alias declaration: ``` type Result = Result; ``` -Because this is in the `std::io` module, the fully qualified alias that we can -use is `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 +Because this is in the `std::io` module, we can use the fully 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: ``` @@ -1641,14 +1831,14 @@ pub trait Write { The type alias helps in two ways: this is easier to write *and* it gives us a consistent interface across all of `std::io`. Because it’s an alias, it is just another `Result`, which means we can use any methods that work on -`Result` with it, and special syntax like `?`. +`Result` with it, as well as special syntax like `?`. -### The Never Type, `!`, that Never Returns +### The `!` Never Type that Never Returns -Rust has a special type named `!`. In type theory lingo, it’s called the *empty -type*, because it has no values. We prefer to call it the *never type*. The name -describes what it does: it stands in the place of the return type when a -function will never return. For example: +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*, +because it stands in the place of the return type when a function will never +return. For example: ``` fn bar() -> ! { @@ -1656,11 +1846,13 @@ fn bar() -> ! { } ``` -This is read as “the function `bar` returns never,†and functions that return -never are called *diverging functions*. We can’t create values of the type `!`, -so `bar` can never possibly return. What use is a type you can never create -values for? If you think all the way back to Chapter 2, we had some code that -looked like this, reproduced here in Listing 19-33: +This is read as “the function `bar` returns never.†Functions that return 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? If you think all the +way back to Chapter 2, we had some code that looked like the code we’ve +reproduced here in Listing 19-34: ``` let guess: u32 = match guess.trim().parse() { @@ -1669,10 +1861,11 @@ let guess: u32 = match guess.trim().parse() { }; ``` -Listing 19-33: A `match` with an arm that ends in `continue` +Listing 19-34: A `match` with an arm that ends in `continue` -At the time, we skipped over some details in this code. In Chapter 6, we -learned that `match` arms must return the same type. This doesn’t work: +At the time, we skipped over some details in this code. In Chapter 6 in “The +`match` Control Flow Operator†section, we covered that `match` arms must all +return the same type. This, for example, doesn’t work: ``` let guess = match guess.trim().parse() { @@ -1681,23 +1874,32 @@ let guess = match guess.trim().parse() { } ``` -What would the type of `guess` be here? It’d have to be both an integer and a -string, and Rust requires that `guess` can only have one type. So what does -`continue` return? Why are we allowed to return a `u32` from one arm in Listing -19-33 and have another arm that ends with `continue`? +The type of `guess` here would have to be both an integer and a string, and +Rust requires that `guess` can only have 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? As you may have guessed, `continue` has a value of `!`. That is, when Rust goes -to compute the type of `guess`, it looks at both of the match arms. The former -has a value of `u32`, and the latter has a value of `!`. Since `!` can never -have a value, Rust is okay with this, and decides that the type of `guess` is -`u32`. The formal way of describing this behavior of `!` is that the never type -unifies with all other types. We’re allowed to end this `match` arm with +to compute the type of `guess`, it looks at both of the match arms, the former +with a value of `u32`, and the latter a value of `!`. Because `!` can never +have a value, Rust decides that the type of `guess` is `u32`. + +The formal way of describing this behavior is that expressions of type `!` can +be coerced into any other type. We’re allowed to end this `match` arm with `continue` because `continue` doesn’t actually return a value; it instead moves control back to the top of the loop, so in the `Err` case, we never actually assign a value to `guess`. -Another use of the never type is `panic!`. Remember the `unwrap` function that -we call on `Option` values to produce a value or panic? Here’s its + + + +The never type is also useful with `panic!`. Remember the `unwrap` function +that we call on `Option` values to produce a value or panic? Here’s its definition: ``` @@ -1711,7 +1913,7 @@ impl Option { } ``` -Here, the same thing happens as in the `match` in Listing 19-33: we know that +Here, the same thing happens as in the `match` in Listing 19-34: we know that `val` has the type `T`, and `panic!` has the type `!`, so the result of the overall `match` expression is `T`. This works because `panic!` doesn’t produce a value; it ends the program. In the `None` case, we won’t be returning a value @@ -1729,69 +1931,77 @@ loop { Here, the loop never ends, so the value of the expression is `!`. This wouldn’t be true if we included a `break`, however, as the loop would terminate when it -gets to the `break`. +got to the `break`. ### Dynamically Sized Types & `Sized` -Because Rust needs to know things like memory layout, there’s a particular -corner of its type system that can be confusing, and that’s the concept of -*dynamically sized types*. Sometimes referred to as ‘DSTs’ or ‘unsized types’, -these types let us talk about types whose size we can only know at runtime. +Due to Rust’s need to know things like how much space to allocate for a value +of a particular type, there’s 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 talk about types whose size we +can only know at runtime. Let’s dig into the details of a dynamically sized type that we’ve been using -this whole book: `str`. That’s right, not `&str`, but `str` on its own. `str` -is a DST; we can’t know how long the string is until runtime. Since we can’t -know that, we can’t create a variable of type `str`, nor can we take an -argument of type `str`. Consider this code, which does not work: +this whole book: `str`. That’s right, not `&str`, but `str` on its own, is a +DST. We can’t know how long the string is until runtime, meaning we can’t +create a variable of type `str`, nor can we take an argument of type `str`. +Consider this code, which does not work: ``` let s1: str = "Hello there!"; let s2: str = "How's it going?"; ``` -These two `str` values would need to have the exact same memory layout, but -they have different lengths: `s1` needs 12 bytes of storage, and `s2` needs 15. -This is why it’s not possible to create a variable holding a dynamically sized -type. + + -So what to do? Well, you already know the answer in this case: the types of -`s1` and `s2` are `&str` rather than `str`. If you think back to Chapter 4, we -said this about `&str`: +Rust needs to know how much memory to allocate for any value of a particular +type, and all values of a type must use the same amount of memory. If we were +allowed to write this code, that would mean these two `str` values would need +to take up the exact same amount of space, but they have different lengths: +`s1` needs 12 bytes of storage, and `s2` needs 15. This is why it’s not +possible to create a variable holding a dynamically sized type. -> ... it’s a reference to an internal position in the String and the number of -> elements that it refers to. +So what to do? You already know the answer in this case: we make the types of +`s1` and `s2` a `&str` rather than `str`. If you think back to the “String +Slices†section of Chapter 4, we said that the slice data structure stores the +starting position and the length of the slice. So while 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 how long -it is. As such, a `&str` has a size we can know 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. This is the general 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. This leads us to the golden -rule of dynamically sized types: we must always put values of dynamically sized -types behind a pointer of some kind. +`T` is located, a `&str` is *two* values: the address of the `str` and its +length. As such, a `&str` has a size we can know 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. This is the general 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. This leads us to the +golden rule of dynamically sized types: we must always put values of +dynamically sized types behind a pointer of some kind. - - -While we’ve talked a lot about `&str`, we can combine `str` with all kinds of -pointers: `Box`, for example, or `Rc`. In fact, you’ve already 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, we mentioned that in order to use traits as trait objects, we have -to put them behind a pointer like `&Trait` or `Box` (`Rc` would -work too). Traits being dynamically sized is the reason we have to do that! +We can combine `str` with all kinds of pointers: `Box`, for example, 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 in order to use +traits as trait objects, we have to put them behind a pointer like `&Trait` or +`Box` (`Rc` would work too). Traits being dynamically sized is +the reason we have to do that! #### The `Sized` Trait -To work with DSTs, Rust has a trait that determines if a type’s size is known -at compile time or not, which is `Sized`. This trait is automatically -implemented for everything the compiler knows the size of at compile time. In -addition, Rust implicitly adds a bound on `Sized` to every generic function. -That is, a generic function definition like this: + + + +To work with DSTs, Rust has a particular trait to determine if a type’s size is +known at compile time or not: the `Sized` trait. This trait is automatically +implemented for everything whose size is known at compile time. In addition, +Rust implicitly adds a bound on `Sized` to every generic function. That is, a +generic function definition like this: ``` fn generic(t: T) { @@ -1821,24 +2031,32 @@ A trait bound on `?Sized` is the opposite of a trait bound on `Sized`; that is, we would read this as “`T` may or may not be `Sized`â€. This syntax is only available for `Sized`, no other traits. -Also note we switched the type of the `t` parameter from `T` to `&T`: since the -type might not be `Sized`, we need to use it behind some kind of pointer. In -this case, we’ve chosen a reference. +Also note we switched the type of the `t` parameter from `T` to `&T`: because +the type might not be `Sized`, we need to use it behind some kind of pointer. +In this case, we’ve chosen a reference. Next let’s talk about functions and closures! ## Advanced Functions & Closures -Finally, let’s discuss some advanced features having to do with functions and +Finally, let’s discuss some advanced features related to functions and closures: function pointers, diverging functions, and returning closures. -### Function pointers +### Function Pointers -We’ve talked about how to pass closures to functions, but you can pass regular -functions to functions too! Functions coerce to the type `fn`, with a lower -case ‘f’ not to be confused with the `Fn` closure trait. `fn` 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-34: + + + +We’ve talked about how to pass closures to functions; you can also pass regular +functions to functions! This 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. +Functions coerce to the type `fn`, with a lower case ‘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: Filename: src/main.rs @@ -1858,7 +2076,7 @@ fn main() { } ``` -Listing 19-34: Using the `fn` type to accept a function pointer as an argument +Listing 19-35: Using the `fn` type to accept a function pointer as an argument This prints `The answer is: 12`. We specify that the parameter `f` in `do_twice` is an `fn` that takes one parameter of type `i32` and returns an @@ -1866,19 +2084,22 @@ This prints `The answer is: 12`. We specify that the parameter `f` in the function name `add_one` as the first argument to `do_twice`. Unlike closures, `fn` is a type rather than a trait, so we specify `fn` as the -parameter type directly rather than declaring a generic type parameter with one -of the `Fn` traits as a trait bound. +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 when calling -a function that expects a closure. Prefer to write functions using a generic -type and one of the closure traits, so that your functions can accept either -functions or closures. An example of a case where you’d only want to accept -`fn` is when interfacing with external code that doesn’t have closures: C -functions can accept functions as arguments, but C doesn’t have closures. +`FnOnce`), so we can always pass a function pointer as an argument for a +function that expects a closure. Prefer to write functions using a generic type +and one of the closure traits, so that your functions can accept either +functions or closures. -For example, if we wanted to use the `map` function to turn a vector of numbers -into a vector of strings, we could use a closure: +An example of a case where you’d 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. + +For an example where we can 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: ``` let list_of_numbers = vec![1, 2, 3]; @@ -1904,17 +2125,17 @@ named `to_string`; here, we’re using the `to_string` function defined in the `ToString` trait, which the standard library has implemented for any type that implements `Display`. -Some people prefer this style, some people prefer the closure. They end up +Some people prefer this style, some people prefer to use closures. They end up with the same code, so use whichever feels more clear to you. ### Returning Closures -Because closures are represented by traits, returning closures is a little -tricky; we can’t do it directly. In most cases where we may want to return a -trait, we can instead use the concrete type that implements the trait of what -we’re returning as the return value of the function. We can’t do that with -closures, though. They don’t have a concrete type that’s returnable; we’re not -allowed to use the function pointer `fn` as a return type, for example. +Closures are represented by traits, which means we can’t return closures +directly. In most cases where we may want to return a trait, we can instead use +the concrete type that implements the trait as the return value of the +function. We can’t do that with closures, though, because they don’t have a +concrete type that’s returnable; we’re not allowed to use the function pointer +`fn` as a return type, for example. This code that tries to return a closure directly won’t compile: @@ -1929,20 +2150,20 @@ The compiler error is: ``` error[E0277]: the trait bound `std::ops::Fn(i32) -> i32 + 'static: std::marker::Sized` is not satisfied - --> :2:25 + --> | -2 | fn returns_closure() -> Fn(i32) -> i32 { - | ^^^^^^^^^^^^^^ the trait `std::marker::Sized` is - not implemented for `std::ops::Fn(i32) -> i32 + 'static` +1 | fn returns_closure() -> Fn(i32) -> i32 { + | ^^^^^^^^^^^^^^ `std::ops::Fn(i32) -> i32 + 'static` + does not have a constant size known at compile-time | - = note: `std::ops::Fn(i32) -> i32 + 'static` does not have a constant size - known at compile-time + = help: the trait `std::marker::Sized` is not implemented for + `std::ops::Fn(i32) -> i32 + 'static` = note: the return type of a function must have a statically known size ``` -The `Sized` trait again! Rust doesn’t know how much space it’ll need to store the -closure. We saw a solution to this in the previous section, though: we can use -a trait object: +Our error references the `Sized` trait again! Rust doesn’t know how much space +it will need to store the closure. We saw a solution to this in the previous +section: we can use a trait object: ``` fn returns_closure() -> Box i32> { @@ -1950,14 +2171,17 @@ fn returns_closure() -> Box i32> { } ``` -For more about trait objects, refer back to Chapter 18. +This code will compile just fine. For more about trait objects, refer back to +the “Trait Objects†section in Chapter 17. ## Summary -Whew! Now we’ve gone over features of Rust that aren’t used very often, but are -available if you need them. We’ve introduced a lot of complex topics so that -when you encounter them in error message suggestions or when reading others’ -code, you’ll at least have seen these concepts and syntax once before. +Whew! Now we’ve gone over features of Rust that aren’t used often, but are +available if you need them in very particular circumstances. We’ve introduced a +lot of complex topics so that, when you encounter them in error message +suggestions or in others’ code, you’ll at least have seen these concepts and +syntax once before. You can use this chapter as a reference to guide you to +your solutions. Now, let’s put everything we’ve learned throughout the book into practice with one more project! diff --git a/src/doc/book/second-edition/src/SUMMARY.md b/src/doc/book/second-edition/src/SUMMARY.md index c7f8306748..3e4db6bc7a 100644 --- a/src/doc/book/second-edition/src/SUMMARY.md +++ b/src/doc/book/second-edition/src/SUMMARY.md @@ -5,6 +5,7 @@ - [Introduction](ch01-00-introduction.md) - [Installation](ch01-01-installation.md) - [Hello, World!](ch01-02-hello-world.md) + - [How Rust is Made and “Nightly Rustâ€](ch01-03-how-rust-is-made-and-nightly-rust.md) - [Guessing Game Tutorial](ch02-00-guessing-game-tutorial.md) diff --git a/src/doc/book/second-edition/src/ch01-00-introduction.md b/src/doc/book/second-edition/src/ch01-00-introduction.md index 1d1848fc40..0008f023e9 100644 --- a/src/doc/book/second-edition/src/ch01-00-introduction.md +++ b/src/doc/book/second-edition/src/ch01-00-introduction.md @@ -1,34 +1,131 @@ # Introduction Welcome to “The Rust Programming Language,†an introductory book about Rust. -Rust is a programming language that’s focused on safety, speed, and -concurrency. Its design lets you create programs that have the performance and -control of a low-level language, but with the powerful abstractions of a -high-level language. These properties make Rust suitable for programmers who -have experience in languages like C and are looking for a safer alternative, as -well as those from languages like Python who are looking for ways to write code -that performs better without sacrificing expressiveness. -Rust performs the majority of its safety checks and memory management decisions -at compile time, so that your program’s runtime performance isn’t impacted. This -makes it useful in a number of use cases that other languages aren’t good at: -programs with predictable space and time requirements, embedding in other -languages, and writing low-level code, like device drivers and operating -systems. It’s also great for web applications: it powers the Rust package -registry site, [crates.io]! We’re excited to see what *you* create with Rust. +Rust is a programming language that helps you write faster, more reliable +software. High-level ergonomics and low-level control are often at odds with +each other in programming language design; Rust stands to challenge that. +Through balancing powerful technical capacity and a great developer experience, +Rust gives you the option to control low-level details (such as memory usage) +without all the hassle traditionally associated with such control. -[crates.io]: https://crates.io/ +## Who Rust is For -This book is written for a reader who already knows how to program in at least -one programming language. After reading this book, you should be comfortable -writing Rust programs. We’ll be learning Rust through small, focused examples -that build on each other to demonstrate how to use various features of Rust as -well as how they work behind the scenes. +Rust is great for many people for a variety of reasons. Let’s discuss a few of +the most important groups. -## Contributing to the book +### Teams of Developers -This book is open source. If you find an error, please don’t hesitate to file an -issue or send a pull request [on GitHub]. Please see [CONTRIBUTING.md] for +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 +developers. In Rust, the compiler plays a gatekeeper role by refusing to +compile code with these kinds of bugs--including concurrency bugs. By working +alongside the compiler, the team can spend more time focusing on the logic of +the program rather than chasing down bugs. + +Rust also brings contemporary developer tools to the systems programming world: + +* Cargo, the included dependency manager and build tool, makes adding, + compiling, and managing dependencies painless and consistent across the Rust + ecosystem. +* Rustfmt ensures a consistent coding style across developers. +* The Rust Language Server powers IDE integration for code completion and + inline error messages. + +By using these and other tools in the Rust ecosystem, developers can be +productive while writing systems-level code. + +### Students + +Rust is for students and people who are interested in learning about systems +concepts. Many people have learned about topics like operating systems +development through Rust. The community is happy to answer student questions. +Through efforts such as this book, the Rust teams want to make systems concepts +more accessible to more people, especially those getting started with +programming. + +### Companies + +Rust is used in production by hundreds of companies, large and small, for a +variety of tasks, such as command line tools, web services, DevOps tooling, +embedded devices, audio and video analysis and transcoding, cryptocurrencies, +bioinformatics, search engines, internet of things applications, machine +learning, and even major parts of the Firefox web browser. + +### Open Source Developers + +Rust is for people who want to build the Rust programming language, community, +developer tools, and libraries. We’d love for you to contribute to the Rust +language. + +### People Who Value Speed and Stability + +By speed, we mean both the speed of the programs that Rust lets you create 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. + +This isn’t a complete list of everyone the Rust language hopes to support, but +these are some of the biggest stakeholders. Overall, Rust’s greatest ambition +is to take trade-offs that have been accepted by programmers for decades and +eliminate the dichotomy. Safety *and* productivity. Speed *and* ergonomics. +Give Rust a try, and see if its choices work for you. + +## Who This Book is For + +This book assumes that you’ve written code in some other programming language, +but doesn’t make any assumptions about which one. We’ve tried to make the +material broadly accessible to those from a wide variety of programming +backgrounds. We don’t spend a lot of time talking about what programming *is* +or how to think about it; someone new to programming entirely would be better +served by reading a book specifically providing an introduction to programming. + +## How to Use This Book + +This book generally assumes that you’re reading it front-to-back, that is, +later chapters build on top of concepts in earlier chapters, and earlier +chapters may not dig into details on a topic, revisiting the topic in a later +chapter. + +There are two kinds of chapters in this book: concept chapters, and project +chapters. In concept chapters, you’ll learn about an aspect of Rust. In the +project chapters, we’ll build small programs together, applying what we’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 Rust as a language. We’ll +cover concepts at a high level, and later chapters will go into them in detail. +If you’re the kind of person who likes to get their hands dirty right away, +Chapter 2 is great for that. If you’re *really* that kind of person, you may +even wish to skip over Chapter 3, which covers features that are very similar +to other programming languages, and go straight to Chapter 4 to learn about +Rust’s ownership system. By contrast, if you’re a particularly meticulous +learner who prefers to learn every detail before moving onto the next, you may +want to skip Chapter 2 and go straight to Chapter 3. + +In the end, there’s no wrong way to read a book: if you want to skip ahead, go +for it! You may have to jump back if you find things confusing. Do whatever +works for you. + +An important part of the process of learning Rust is learning how to read the +error messages that the compiler gives you. As such, we’ll be showing a lot of +code that doesn’t compile, and the error message the compiler will show you in +that situation. As such, if you pick a random example, it may not compile! +Please read the surrounding text to make sure that you didn’t happen to pick +one of the in-progress examples. + +Finally, there are some appendices. These contain useful information about the +language in a more reference-like format. + +## Contributing to the Book + +This book is open source. If you find an error, please don’t hesitate to file +an issue or send a pull request [on GitHub]. Please see [CONTRIBUTING.md] for more details. [on GitHub]: https://github.com/rust-lang/book 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 86a1e8c460..8cf992bc7a 100644 --- a/src/doc/book/second-edition/src/ch01-01-installation.md +++ b/src/doc/book/second-edition/src/ch01-01-installation.md @@ -2,36 +2,52 @@ The first step to using Rust is to install it. You’ll need an internet connection to run the commands in this chapter, as we’ll be downloading Rust -from the internet. +from the internet. We’ll actually be installing Rust using `rustup`, a +command-line tool for managing Rust versions and associated tools. -We’ll be showing off a number of commands using a terminal, and those lines all -start with `$`. You don’t need to type in the `$` character; they are there to indicate -the start of each command. You’ll see many tutorials and examples around the web -that follow 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. +The following steps will install the latest stable version of the Rust +compiler. The examples and output shown in this book used stable Rust 1.21.0. +Due to Rust’s stability guarantees, which we’ll discuss further in the “How +Rust is Made†section later in this chapter, all of the examples that compile +will continue to compile with newer versions of Rust. The output may differ +slightly as error messages and warnings are often improved. In other words, the +newer, stable version of Rust you will install with these steps should work as +expected with the content of this book. -### Installing on Linux or Mac +> #### Command Line Notation +> +> We’ll be showing off a number of commands using a terminal, and those lines +> all start with `$`. You don’t need to type in the `$` character; they are +> there to indicate the start of each command. You’ll see many tutorials and +> examples around the web that follow 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 `$`. -If you’re on Linux or a Mac, all you need to do is open a terminal and type -this: +### Installing Rustup on Linux or Mac + +If you’re on Linux or a Mac, 99% of what you need to do is open a terminal and +type this: ```text $ curl https://sh.rustup.rs -sSf | sh ``` -This will download a script and start the installation. You may be prompted for -your password. If it all goes well, you’ll see this appear: +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: ```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. +Of course, if you distrust using `curl URL | sh` to install software, you can +download, inspect, and run the script however you like. -The installation script automatically adds Rust to your system PATH after your next login. -If you want to start using Rust right away, run the following command in your shell: +The installation script automatically adds Rust to your system PATH after your +next login. If you want to start using Rust right away, run the following +command in your shell: ```text $ source $HOME/.cargo/env @@ -43,26 +59,39 @@ Alternatively, add the following line to your `~/.bash_profile`: $ export PATH="$HOME/.cargo/bin:$PATH" ``` -### Installing on Windows +Finally, you’ll need a linker of some kind. You likely have one installed. If +not, when you compile a Rust program, you’ll get errors that a linker could not +be executed. Check your platform’s documentation for how to install a C +compiler; they usually come with the correct linker as well, given that C needs +one. You may want to install a C compiler regardless of your need for only a +linker; some common Rust packages depend on C code and will need a C compiler +too. -On Windows, go to [https://rustup.rs](https://rustup.rs/) and -follow the instructions to download rustup-init.exe. Run that and follow the -rest of the instructions it gives you. +### Installing Rustup on Windows -The rest of the Windows-specific commands in the book will assume that you are -using `cmd` as your shell. If you use a different shell, you may be able to run -the same commands that Linux and Mac users do. If neither work, consult the -documentation for the shell you are using. +On Windows, go to [https://www.rust-lang.org/en-US/install.html][install] and +follow the instructions. You’ll also need the C++ build tools for Visual Studio +2013 or later. The easiest way to acquire the build tools is by installing +[Build Tools for Visual Studio 2017][visualstudio] which provides only the +Visual C++ build tools. Alternately, you can [install][visualstudio] Visual +Studio 2017, Visual Studio 2015, or Visual Studio 2013 and during installation +select the desktop development with C++ workload. -### Custom installations +[install]: https://www.rust-lang.org/en-US/install.html +[visualstudio]: https://www.visualstudio.com/downloads/ -If you have reasons for preferring not to use rustup.rs, please see [the Rust +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. ### Updating -Once you have Rust installed, updating to the latest version is easy. -From your shell, run the update script: +Once you have Rust installed via `rustup`, updating to the latest version is +easy. From your shell, run the update script: ```text $ rustup update @@ -70,8 +99,8 @@ $ rustup update ### Uninstalling -Uninstalling Rust is as easy as installing it. From your shell, run -the uninstall script: +Uninstalling Rust and Rustup is as easy as installing them. From your shell, +run the uninstall script: ```text $ rustup self uninstall @@ -79,7 +108,7 @@ $ rustup self uninstall ### Troubleshooting -If you’ve got Rust installed, you can open up a shell, and type this: +To check that you have Rust installed, you can open up a shell and type this: ```text $ rustc --version @@ -92,8 +121,7 @@ similar to this for the latest stable version at the time you install: rustc x.y.z (abcabcabc yyyy-mm-dd) ``` -If you see this, Rust has been installed successfully! -Congrats! +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. @@ -102,19 +130,20 @@ If it still isn’t working, there are a number of places where 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]. +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 [users]: https://users.rust-lang.org/ [stackoverflow]: http://stackoverflow.com/questions/tagged/rust -### Local documentation +### Local Documentation 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, use the API documentation to find out! +not sure what it does or how to use it, use the API (Application Programming +Interface) documentation to find out! 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 d262d94bd4..e124ddf4f3 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 @@ -7,15 +7,19 @@ tradition. > 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 to the command line, feel free to use your -> favorite IDE. +> 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 +> 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 this book, we’d 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 directory for this particular project: +First, make a directory to put your Rust code in. Rust doesn’t care where your +code lives, but for this book, we’d 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 +inside that for the “Hello, world!†project: Linux and Mac: @@ -29,8 +33,8 @@ $ cd hello_world Windows CMD: ```cmd -> mkdir %USERPROFILE%\projects -> cd %USERPROFILE%\projects +> mkdir "%USERPROFILE%\projects" +> cd /d "%USERPROFILE%\projects" > mkdir hello_world > cd hello_world ``` @@ -51,7 +55,8 @@ 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*. -Now open the *main.rs* file you just created, and type the following code: +Now open the *main.rs* file you just created, and enter the code shown in +Listing 1-1: Filename: main.rs @@ -61,8 +66,10 @@ fn main() { } ``` -Save the file, and go back to your terminal window. On Linux or OSX, enter the -following commands: +Listing 1-1: A program that prints “Hello, world!†+ +Save the file, and go back to your terminal window. On Linux or macOS, enter +the following commands: ```text $ rustc main.rs @@ -70,10 +77,17 @@ $ ./main Hello, world! ``` -On Windows, run `.\main.exe` instead of `./main`. Regardless of your -operating system, you should see the string `Hello, world!` print to the -terminal. If you did, then congratulations! You’ve officially written a Rust -program. That makes you a Rust programmer! Welcome! +On Windows, use `.\main.exe` instead of `./main`. + +```powershell +> rustc main.rs +> .\main.exe +Hello, world! +``` + +Regardless of your operating system, you should see the string `Hello, world!` +print to the terminal. If you did, then congratulations! You’ve officially +written a Rust program. That makes you a Rust programmer! Welcome! ### Anatomy of a Rust Program @@ -87,17 +101,23 @@ fn main() { ``` These lines define a *function* in Rust. The `main` function is special: it’s -the first thing that is run for every executable Rust program. The first line -says, “I’m declaring a function named `main` that has no parameters and returns -nothing.†If there were parameters, their names would go inside the -parentheses, `(` and `)`. +the first code that is run for 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 `)`. 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 put the opening curly bracket on the same line as the function declaration, with one space in between. -Inside the `main` function: +> 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. + +Inside the `main` function, we have this code: ```rust println!("Hello, world!"); @@ -107,12 +127,29 @@ 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. -The second important part is `println!`. This is calling a Rust *macro*, -which is how metaprogramming is done in Rust. If it were calling a function -instead, it would look like this: `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 means that you’re calling a macro instead of a -normal function. +The second important part is `println!`. This is calling a Rust *macro*, which +is how metaprogramming is done in Rust. If it were calling a function instead, +it would look like this: `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 means that you’re calling a macro instead of a normal function. + +> ### Why `println!` is a Macro +> +> There are multiple reasons why `println!` is a macro rather than a function, +> and we haven’t really explained Rust yet, so it’s not exactly obvious. Here +> are the reasons: +> +> * The string passed to `println!` can have formatting specifiers in it, +> and those are checked at compile-time. +> * Rust functions can only have a fixed number of arguments, but `println!` +> (and macros generally) can take a variable number. +> * The formatting specifiers can have named arguments, which Rust functions +> cannot. +> * It implicitly takes its arguments by reference even when they’re passed +> by value. +> +> If none of this makes sense, don’t worry about it. We’ll cover these concepts +> in more detail later. Next is `"Hello, world!"` which is a *string*. We pass this string as an argument to `println!`, which prints the string to the screen. Easy enough! @@ -123,8 +160,8 @@ over, and the next one is ready to begin. Most lines of Rust code end with a ### Compiling and Running Are Separate Steps -In “Writing and Running a Rust Programâ€, we showed you how to run a newly -created program. We’ll break that process down and examine each step now. +In the “Writing and Running a Rust Program†section, we showed you how to run a +newly created program. We’ll break that process down and examine each step now. Before running a Rust program, you have to compile it. You can use the Rust compiler by entering the `rustc` command and passing it the name of your source @@ -135,16 +172,18 @@ $ 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 should output a binary -executable, which you can see on Linux or OSX by entering the `ls` command in -your shell as follows: +`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: ```text $ ls main main.rs ``` -On Windows, you’d enter: +With CMD on Windows, you’d enter: ```cmd > dir /B %= the /B option says to only show the file names =% @@ -153,9 +192,9 @@ 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 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: ```text $ ./main # or .\main.exe on Windows @@ -167,15 +206,15 @@ 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 it 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 +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. 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 your project has -and make it easy to share your code with other people and projects. Next, we’ll +grows, you’ll want to be able to manage all of the options your project has and +make it easy to share your code with other people and projects. Next, we’ll introduce you to a tool called Cargo, which will help you write real-world Rust programs. @@ -193,10 +232,10 @@ care of building your code. As you write more complex Rust programs, you’ll want to add dependencies, and if you start off using Cargo, that will be a lot easier to do. -As the vast, vast majority of Rust projects use Cargo, we will assume that +As the vast majority of Rust projects use Cargo, we will assume that you’re using it for the rest of the book. Cargo comes installed with Rust -itself, if you used the official installers as covered in the Installation -chapter. If you installed Rust through some other means, you can check if you +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 typing the following into your terminal: ```text @@ -213,16 +252,16 @@ Let’s create a new project using Cargo and look at how it differs from our project in `hello_world`. Go back to your projects directory (or wherever you decided to put your code): -Linux and Mac: +Linux, Mac, and PowerShell: ```text $ cd ~/projects ``` -Windows: +CMD for Windows: ```cmd -> cd %USERPROFILE%\projects +> cd \d "%USERPROFILE%\projects" ``` And then on any operating system run: @@ -234,19 +273,20 @@ $ cd hello_cargo We passed the `--bin` argument to `cargo new` because our goal is to make an executable application, as opposed to a library. Executables are binary -executable files often called just *binaries*. We’ve given `hello_cargo` -as the name for our project, and Cargo creates its files in a directory -of the same name that we can then go into. +executable files often called just *binaries*. We’ve given `hello_cargo` as the +name for our project, and Cargo creates its files in a directory of the same +name that we can then go into. If we list the files in the *hello_cargo* directory, we can 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 in the *hello_cargo* directory for us, along with a *.gitignore* -file; you can change this to use a different version control system, or no -version control system, by using the `--vcs` flag. +file. 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. -Open up *Cargo.toml* in your text editor of choice. It should look something -like this: +Open up *Cargo.toml* in your text editor of choice. It should look similar to +the code in Listing 1-2: Filename: Cargo.toml @@ -259,9 +299,11 @@ authors = ["Your Name "] [dependencies] ``` +Listing 1-2: Contents of *Cargo.toml* generated by `cargo +new` + This file is in the [*TOML*][toml] (Tom’s Obvious, Minimal -Language) format. TOML is similar to INI but has some extra goodies and is used -as Cargo’s configuration format. +Language) format. TOML is used as Cargo’s configuration format. [toml]: https://github.com/toml-lang/toml @@ -279,7 +321,7 @@ The last line, `[dependencies]`, is the start of a section for you to list any *crates* (which is what we call packages of Rust code) that your project will depend on so that Cargo knows to download and compile those too. We won’t need any other crates for this project, but we will in the guessing game tutorial in -the next chapter. +Chapter 2. Now let’s look at *src/main.rs*: @@ -291,9 +333,9 @@ fn main() { } ``` -Cargo has generated a “Hello World!†for you, just like the one we wrote -earlier! So that part is the same. The differences between our previous project -and the project generated by Cargo that we’ve seen so far are: +Cargo has generated a “Hello World!†for you, just like the one we wrote in +Listing 1-1! So that part is the same. The differences between our previous +project and the project generated by Cargo that we’ve seen so far are: - Our code goes in the *src* directory - The top level contains a *Cargo.toml* configuration file @@ -320,8 +362,9 @@ $ cargo build Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs ``` -This should have created an executable file in *target/debug/hello_cargo* (or -*target\\debug\\hello_cargo.exe* on Windows), which you can run with this command: +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: ```text $ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows @@ -331,24 +374,14 @@ 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 looks like this: - -Filename: Cargo.lock - -```toml -[root] -name = "hello_cargo" -version = "0.1.0" -``` - -Cargo uses the *Cargo.lock* to keep track of dependencies in your application. -This project doesn’t have dependencies, so the file is a bit sparse. -Realistically, you won’t ever need to touch this file yourself; just let Cargo -handle it. +at the top level called *Cargo.lock*. Cargo uses *Cargo.lock* to keep track of +the exact versions of dependencies used to build 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. 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: +`./target/debug/hello_cargo`, but we can also use `cargo run` to compile and +then run: ```text $ cargo run @@ -360,7 +393,7 @@ 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 something like +rebuilt the project before running it, and you would have seen output like this: ```text @@ -371,10 +404,26 @@ $ cargo run Hello, world! ``` +Finally, there’s `cargo check`. This will quickly check your code to make sure +that it compiles, but not bother producing an executable: + +```text +$ cargo check + Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) + 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 Cargo can skip the entire step of producing the +executable. If we’re checking our work throughout the process of writing the +code, this will speed things up! As such, many Rustaceans run `cargo check` 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. + So a few more differences we’ve now seen: -- Instead of using `rustc`, build a project using `cargo build` (or build and - run it in one step with `cargo run`) +- Instead of using `rustc`, build a project using `cargo build` or + `cargo check` (or build and run it 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. @@ -390,10 +439,10 @@ executable in *target/release* instead of *target/debug*. These optimizations make your Rust code run faster, but turning them on makes your program take longer to compile. 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 -building the final program you’ll give to a user that won’t be rebuilt and -that we want to 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*. +building the final program you’ll give to a user that won’t be rebuilt and that +we want to 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*. ### Cargo as Convention @@ -401,10 +450,13 @@ 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 Cargo, you can just run `cargo build`, and it should work the -right way. Even though this project is simple, it now uses much of the real +right way. + +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, you can get -started with virtually all Rust projects you want to work -on with the following commands: +started with virtually all Rust projects you want to work on with the following +commands to check out the code using Git, change into the project directory, +and build: ```text $ git clone someurl.com/someproject @@ -412,7 +464,7 @@ $ cd someproject $ cargo build ``` -> Note: If you want to look at Cargo in more detail, check out the official -[Cargo guide], which covers all of its features. +If you want to look at Cargo in more detail, check out [its documentation], +which covers all of its features. -[Cargo guide]: http://doc.crates.io/guide.html +[its documentation]: https://doc.rust-lang.org/cargo/ diff --git a/src/doc/book/second-edition/src/ch01-03-how-rust-is-made-and-nightly-rust.md b/src/doc/book/second-edition/src/ch01-03-how-rust-is-made-and-nightly-rust.md new file mode 100644 index 0000000000..d5c3ec86b1 --- /dev/null +++ b/src/doc/book/second-edition/src/ch01-03-how-rust-is-made-and-nightly-rust.md @@ -0,0 +1,226 @@ +## How Rust is Made and “Nightly Rust†+ +Before we dive into the language itself, we’d like to finish up the +introductory chapter by talking about how Rust is made, and how that affects +you as a Rust developer. We mentioned in the “Installation†section 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! + +### Stability Without Stagnation + +As a language, Rust cares a *lot* about the stability of your code. We want +Rust to be a rock-solid foundation you can build on, and if things were +constantly changing, that would be impossible. At the same time, if we can’t +experiment with new features, we may not find out important flaws until after +their release, when we can no longer change things. + +Our solution to this problem is what we call “stability without stagnation†and +is the way we can change and improve Rust while making sure that using Rust +stays nice, stable, and boring. + +Our guiding principle for Rust releases is this: you should never have to fear +upgrading to a new version of stable Rust. Each upgrade should be painless. At +the same time, the upgrade should bring you new features, fewer bugs, and +faster compile times. + +### Choo, Choo! Release Channels and Riding the Trains + +Rust development operates on a *train schedule*. That is, all development is +done on the `master` branch of the Rust repository. Releases follow a software +release train model, which has been used by Cisco IOS and other software +projects. There are three *release channels* for Rust: + +* Nightly +* Beta +* Stable + +Most Rust developers primarily use the stable channel, but those who want to +try out experimental new features may use nightly or beta. + +Here’s an example of how the development and release process works: let’s +assume that the Rust team is working on the release of Rust 1.5. That release +happened in December of 2015, but it will provide us with realistic version +numbers. A new feature is added to Rust: a new commit lands on the `master` +branch. Each night, a new nightly version of Rust is produced. Every day is a +release day, and these releases are created by our release infrastructure +automatically. So as time passes, our releases look like this, once a night: + +```text +nightly: * - - * - - * +``` + +Every six weeks, it’s time to prepare a new release! The `beta` branch of the +Rust repository branches off from the `master` branch used by nightly. Now, +there are two releases: + +```text +nightly: * - - * - - * + | +beta: * +``` + +Most Rust users do not use beta releases actively, but test against beta in +their CI system to help Rust discover possible regressions. In the meantime, +there’s still a nightly release every night: + +```text +nightly: * - - * - - * - - * - - * + | +beta: * +``` + +Let’s say a regression is found. Good thing we had some time to test the beta +release before the regression snuck into a stable release! The fix is applied +to `master`, so that nightly is fixed, and then the fix is backported to the +`beta` branch, and a new release of beta is produced: + +```text +nightly: * - - * - - * - - * - - * - - * + | +beta: * - - - - - - - - * +``` + +Six weeks after the first beta was created, it’s time for a stable release! The +`stable` branch is produced from the `beta` branch: + +```text +nightly: * - - * - - * - - * - - * - - * - * - * + | +beta: * - - - - - - - - * + | +stable: * +``` + +Hooray! Rust 1.5 is done! However, we’ve forgotten one thing: because the six +weeks have gone by, we also need a new beta of the *next* version of Rust, 1.6. +So after `stable` branches off of `beta`, the next version of `beta` branches +off of `nightly` again: + +```text +nightly: * - - * - - * - - * - - * - - * - * - * + | | +beta: * - - - - - - - - * * + | +stable: * +``` + +This is called the “train model†because every six weeks, a release “leaves the +stationâ€, but still has to take a journey through the beta channel before it +arrives as a stable release. + +Rust releases every six weeks, like clockwork. If you know the date of one Rust +release, you can know the date of the next one: it’s six weeks later. A nice +aspect of having releases scheduled every six weeks is that the next train is +coming soon. If a feature happens to miss a particular release, there’s no need +to worry: another one is happening in a short time! This helps reduce pressure +to sneak possibly unpolished features in close to the release deadline. + +Thanks to this process, you can always check out the next build of Rust and +verify for yourself that it’s easy to upgrade to: if a beta release doesn’t +work as expected, you can report it to the team and get it fixed before the +next stable release happens! Breakage in a beta release is relatively rare, but +`rustc` is still a piece of software, and bugs do exist. + +### Unstable Features + +There’s one more catch with this release model: unstable features. Rust uses a +technique called “feature flags†to determine what features are enabled in a +given release. If a new feature is under active development, it lands on +`master`, and therefore, in nightly, but behind a *feature flag*. If you, as a +user, wish to try out the work-in-progress feature, you can, but you must be +using a nightly release of Rust and annotate your source code with the +appropriate flag to opt in. + +If you’re using a beta or stable release of Rust, you can’t use any feature +flags. This is the key that allows us to get practical use with new features +before we declare them stable forever. Those who wish to opt into the bleeding +edge can do so, and those who want a rock-solid experience can stick with +stable and know that their code won’t break. Stability without stagnation. + +This book only contains information about stable features, as in-progress +features are still changing, and surely they’ll be different between when this +book was written and when they get enabled in stable builds. You can find +documentation for nightly-only features online. + +### Rustup and the Role of Rust Nightly + +Rustup makes it easy to change between different release channels of Rust, on a +global or per-project basis. By default, you’ll have stable Rust installed. To +install nightly, for example: + +```text +$ 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: + +```powershell +> rustup toolchain list +stable-x86_64-pc-windows-msvc (default) +beta-x86_64-pc-windows-msvc +nightly-x86_64-pc-windows-msvc +``` + +As you can see, the stable toolchain is the default. Most Rust users use stable +most of the time. You might want to use stable most of the time, but use +nightly on a specific project, because you care about a cutting-edge feature. +To do so, you can use `rustup override` in that project’s directory to set the +nightly toolchain as the one `rustup` should use when you’re in that directory: + +```text +$ cd ~/projects/needs-nightly +$ rustup override add nightly +``` + +Now, every time you call `rustc` or `cargo` inside of +*~/projects/needs-nightly*, `rustup` will make sure that you are using nightly +Rust, rather than your default of stable Rust. This comes in handy when you +have a lot of Rust projects! + +### The RFC Process and Teams + +So how do you learn about these new features? Rust’s development model follows +a *Request For Comments (RFC) process*. If you’d like an improvement in Rust, +you can write up a proposal, called an RFC. + +Anyone can write RFCs to improve Rust, and the proposals are reviewed and +discussed by the Rust team, which is comprised of many topic subteams. There’s +a full list of the teams [on Rust’s +website](https://www.rust-lang.org/en-US/team.html), which includes teams for +each area of the project: language design, compiler implementation, +infrastructure, documentation, and more. The appropriate team reads the +proposal and the comments, writes some comments of their own, and eventually, +there’s consensus to accept or reject the feature. + +If the feature is accepted, an issue is opened on the Rust repository, and +someone can implement it. The person who implements it very well may not be the +person who proposed the feature in the first place! When the implementation is +ready, it lands on the `master` branch behind a feature gate, as we discussed +in the “Unstable Features†section. + +After some time, once Rust developers who use nightly releases have been able +to try out the new feature, team members will discuss the feature, how it’s +worked out on nightly, and decide if it should make it into stable Rust or not. +If the decision is to move forward, the feature gate is removed, and the +feature is now considered stable! It rides the trains into a new stable release +of Rust. + +## Summary + +You’re already off to a great start on your Rust journey! In this chapter, +you’ve: + +* Learned what makes Rust unique +* Installed the latest stable version of Rust +* Written a “Hello, world!†program using both `rustc` directly and using + the conventions of `cargo` +* Found out about how Rust is developed + +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. + 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 3753f9aa10..e9becae732 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 @@ -770,8 +770,9 @@ user must press the enter key to satisfy `read_line`. When the user presses enter, a newline character is added to the string. For example, if the user types 5 and presses enter, -`guess` looks like this: `5\n`. The `\n` represents “newline,†the enter key. -The `trim` method eliminates `\n`, resulting in just `5`. +`guess` looks like this: `5\n`. The `\n` represents “newline,†the +enterkey. The `trim` method eliminates `\n`, +resulting in just `5`. The [`parse` method on strings][parse] parses a string into some kind of number. Because this method can parse a variety of number types, we @@ -870,7 +871,7 @@ exactly what we told it to do: ask for another guess forever! It doesn’t seem like the user can quit! The user could always halt the program by using the keyboard shortcut -ctrl-C. But there’s another way to escape this +ctrl-c. But there’s another way to escape this insatiable monster that we mentioned in the `parse` discussion in “Comparing the Guess to the Secret Numberâ€: if the user enters a non-number answer, the program will crash. The user can take advantage of that in order to quit, as shown here: diff --git a/src/doc/book/second-edition/src/ch03-05-control-flow.md b/src/doc/book/second-edition/src/ch03-05-control-flow.md index 27d324e5b9..749be3fea8 100644 --- a/src/doc/book/second-edition/src/ch03-05-control-flow.md +++ b/src/doc/book/second-edition/src/ch03-05-control-flow.md @@ -283,7 +283,7 @@ fn main() { When we run this program, we’ll see `again!` printed over and over continuously until we stop the program manually. Most terminals support a keyboard shortcut, -ctrl-C, to halt a program that is stuck in a +ctrl-c, to halt a program that is stuck in a continual loop. Give it a try: ```text @@ -298,7 +298,7 @@ again! ^Cagain! ``` -The symbol `^C` represents where you pressed ctrl-C +The symbol `^C` represents where you pressed ctrl-c . You may or may not see the word `again!` printed after the `^C`, depending on where the code was in the loop when it received the halt signal. 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 905adeff4a..ceea8cc981 100644 --- a/src/doc/book/second-edition/src/ch08-01-vectors.md +++ b/src/doc/book/second-edition/src/ch08-01-vectors.md @@ -194,7 +194,7 @@ to the first element would be pointing to deallocated memory. The borrowing rules prevent programs from ending up in that situation. > Note: For more on the implementation details of the `Vec` type, see “The -> Nomicon†at https://doc.rust-lang.org/stable/nomicon/vec.html. +> Rustonomicon†at https://doc.rust-lang.org/stable/nomicon/vec.html. ### Iterating Over the Values in a Vector 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 eecf0ef59d..bb710e3c1c 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 @@ -50,7 +50,7 @@ example: ```rust use std::net::IpAddr; -let home = "127.0.0.1".parse::().unwrap(); +let home: IpAddr = "127.0.0.1".parse().unwrap(); ``` We’re creating an `IpAddr` instance by parsing a hardcoded string. We can see 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 b90879af15..7eddcb291a 100644 --- a/src/doc/book/second-edition/src/ch10-02-traits.md +++ b/src/doc/book/second-edition/src/ch10-02-traits.md @@ -187,7 +187,7 @@ behavior. When we implement the trait on a particular type, we can choose to keep or override each method’s default behavior. Listing 10-15 shows how we could have chosen to specify a default string for -the `summary` method of the `Summarize` trait instead of choosing to only +the `summary` method of the `Summarizable` trait instead of choosing to only define the method signature like we did in Listing 10-12: Filename: lib.rs @@ -508,7 +508,7 @@ impl ToString for T { ``` Because the standard library has this blanket implementation, we can call the -`to_string` method defined by the `ToString` type on any type that implements +`to_string` method defined by the `ToString` trait on any type that implements the `Display` trait. For example, we can turn integers into their corresponding `String` values like this since integers implement `Display`: 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 33a4bf510b..292b17961d 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 @@ -81,17 +81,15 @@ Listing 10-18 with annotations showing the lifetimes of the variables: ```rust,ignore { - let r; // -------+-- 'a - // | - { // | - let x = 5; // -+-----+-- 'b - r = &x; // | | - } // -+ | - // | - println!("r: {}", r); // | - // | - // -------+ -} + let r; // -------+-- 'a + // | + { // | + let x = 5; // -+-----+-- 'b + r = &x; // | | + } // -+ | + // | + println!("r: {}", r); // | +} // -------+ ``` Listing 10-19: Annotations of the lifetimes of `r` and 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 0561c13d51..2a3c361767 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 @@ -127,7 +127,7 @@ 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*. -Listing12-6 shows the addition of a struct named `Config` defined to have +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: @@ -193,8 +193,8 @@ trade-off. > make these copies only once, and our filename and query string are very > small. It’s better to have a working program that’s a bit inefficient than to > try to hyperoptimize code on your first pass. As you become more experienced -> with Rust, it’ll be easier to start with the desirable solution, but for now, -> it’s perfectly acceptable to call `clone`. +> with Rust, it’ll be easier to start with the most efficient solution, but for +> now, it’s perfectly acceptable to call `clone`. We’ve updated `main` so it places the instance of `Config` returned by `parse_config` into a variable named `config`, and we updated the code that @@ -443,8 +443,8 @@ Great! This output is much friendlier for our users. Now that we’ve finished refactoring the configuration parsing, let’s turn to the program’s logic. As we stated in “Separation of Concerns for Binary -Projects†on page XX, we’ll extract a function named `run` that will hold all -the logic currently in the `main` function that isn’t involved with setting up +Projectsâ€, we’ll extract a function named `run` that will hold all the logic +currently in the `main` function that isn’t involved with setting up configuration or handling errors. When we’re done, `main` will be concise and easy to verify by inspection, and we’ll be able to write tests for all the other logic. @@ -583,9 +583,9 @@ fn main() { We use `if let` rather than `unwrap_or_else` to check whether `run` returns an `Err` value and call `process::exit(1)` if it does. The `run` function doesn’t return a value that we want to `unwrap` in the same way that `Config::new` -returns the `Config` instance. Because `run` returns a `()` in the success -case, we only care about detecting an error, so we don’t need `unwrap_or_else` -to return the unwrapped value because it would only be `()`. +returns the `Config` instance. Because `run` returns `()` in the success case, +we only care about detecting an error, so we don’t need `unwrap_or_else` to +return the unwrapped value because it would only be `()`. The bodies of the `if let` and the `unwrap_or_else` functions are the same in both cases: we print the error and exit. @@ -605,7 +605,8 @@ Let’s move all the code that isn’t the `main` function from *src/main.rs* to * The `Config::new` function definition 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): +(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: Filename: src/lib.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 4244f879c4..629c0b1f01 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 will return only the lines from the text that contain the query. -Listing 12-15 shows this test: +Listing 12-15 shows this test, which won't compile yet: Filename: src/lib.rs @@ -125,15 +125,15 @@ 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 “Validating -References with Lifetimes†in Chapter 10 on page XX. +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: ```text $ cargo test ---warnings-- Compiling minigrep v0.1.0 (file:///projects/minigrep) +--warnings-- Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs Running target/debug/deps/minigrep-abcabcabc 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 41fd2ae199..92e3600201 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 @@ -12,7 +12,7 @@ once and have all their searches be case insensitive in that terminal session. We want to add a new `search_case_insensitive` function that we’ll call when 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 +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: @@ -172,7 +172,7 @@ won’t compile yet: # case_sensitive: bool, # } # -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(); diff --git a/src/doc/book/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md b/src/doc/book/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md index 342d865bf0..f9b2ed3d1d 100644 --- a/src/doc/book/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md +++ b/src/doc/book/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md @@ -2,7 +2,7 @@ At the moment we’re writing all of our output to the terminal using the `println!` function. Most terminals provide two kinds of output: *standard -out**put* (`stdout`) for general information and *standard error* (`stderr`) +output* (`stdout`) for general information and *standard error* (`stderr`) for error messages. This distinction enables users to choose to direct the successful output of a program to a file but still print error messages to the screen. @@ -120,4 +120,3 @@ nicely, and be well tested. Next, we’ll explore some Rust features that were influenced by functional languages: closures and iterators. - 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 10edac3304..59ffde6444 100644 --- a/src/doc/book/second-edition/src/ch13-01-closures.md +++ b/src/doc/book/second-edition/src/ch13-01-closures.md @@ -753,7 +753,7 @@ three `Fn` traits as follows: closure must take ownership of these variables and move them into the closure when it is defined. The `Once` part of the name represents the fact that the closure can’t take ownership of the same variables more than once, so it can - only be called one time. + be called only once. * `Fn` borrows values from the environment immutably. * `FnMut` can change the environment because it mutably borrows values. diff --git a/src/doc/book/second-edition/src/ch14-00-more-about-cargo.md b/src/doc/book/second-edition/src/ch14-00-more-about-cargo.md index 3a6da6ace2..c6e66ef12a 100644 --- a/src/doc/book/second-edition/src/ch14-00-more-about-cargo.md +++ b/src/doc/book/second-edition/src/ch14-00-more-about-cargo.md @@ -1,14 +1,15 @@ -# More about Cargo and Crates.io +# More About Cargo and Crates.io So far we’ve used only the most basic features of Cargo to build, run, and test -our code, but it can do a lot more. Here we’ll go over some of its other, more -advanced features to show you how to: +our code, but it can do a lot more. In this chapter, we’ll discuss some of its +other, more advanced features to show you how to: * Customize your build through release profiles -* Publish libraries on crates.io -* Organize larger projects with workspaces -* Install binaries from crates.io -* Extend Cargo with your own custom commands +* Publish libraries on [crates.io](https://crates.io) +* Organize large projects with workspaces +* Install binaries from [crates.io](https://crates.io) +* Extend Cargo using custom commands -Cargo can do even more than what we can cover in this chapter too, so for a -full explanation, see [its documentation](https://doc.rust-lang.org/cargo/). +Cargo can do even more than what we cover in this chapter, so for a full +explanation of all its features, see [its +documentation](https://doc.rust-lang.org/cargo/). 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 e269cf517f..4e4f4cd679 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 @@ -1,18 +1,17 @@ ## Customizing Builds with Release Profiles -In Rust *release profiles* are pre-defined, and customizable, profiles with -different configurations, to allow the programmer more control over various -options for compiling your code. Each profile is configured independently of +In Rust, *release profiles* are predefined and customizable profiles with +different configurations that allow a programmer to have more control over +various options for compiling code. Each profile is configured independently of the others. -Cargo has two main profiles you should know about: the `dev` profile Cargo uses -when you run `cargo build`, and the `release` profile Cargo uses when you run -`cargo build --release`. The `dev` profile is defined with good defaults for -developing, and likewise the `release` profile has good defaults for release -builds. +Cargo has two main profiles: the `dev` profile Cargo uses when you run `cargo +build` and the `release` profile Cargo uses when you run `cargo build +--release`. The `dev` profile is defined with good defaults for developing, and +the `release` profile has good defaults for release builds. -These names may be familiar from the output of your builds, which shows the -profile used in the build: +These profile names might be familiar from the output of your builds, which +shows the profile used in the build: ```text $ cargo build @@ -21,16 +20,14 @@ $ cargo build --release Finished release [optimized] target(s) in 0.0 secs ``` -The “dev†and “release†notifications here indicate that the compiler is using -different profiles. - -### Customizing Release Profiles +The `dev` and `release` shown in this build output indicate that the compiler +is using different profiles. Cargo has default settings for each of the profiles that apply when there aren’t any `[profile.*]` sections in the project’s *Cargo.toml* file. By adding -`[profile.*]` sections for any profile we want to customize, we can choose to -override any subset of the default settings. For example, here are the default -values for the `opt-level` setting for the `dev` and `release` profiles: +`[profile.*]` sections for any profile we want to customize, we can override +any subset of the default settings. For example, here are the default values +for the `opt-level` setting for the `dev` and `release` profiles: Filename: Cargo.toml @@ -42,20 +39,20 @@ opt-level = 0 opt-level = 3 ``` -The `opt-level` setting controls how many optimizations Rust will apply to your -code, with a range of zero to three. Applying more optimizations makes -compilation take longer, so if you’re in development and compiling very often, -you’d want compiling to be fast at the expense of the resulting code running -slower. That’s why the default `opt-level` for `dev` is `0`. When you’re ready -to release, it’s better to spend more time compiling. You’ll only be compiling -in release mode once, and running the compiled program many times, so release -mode trades longer compile time for code that runs faster. That’s why the -default `opt-level` for the `release` profile is `3`. +The `opt-level` setting controls the number of optimizations Rust will apply to +your code with a range of zero to three. Applying more optimizations extends +compiling time, so if you’re in development and compiling your code often, you +want faster compiling even at the expense of the resulting code running 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 and run the compiled program many times, so +release mode trades longer compile time for code that runs faster. That is the +reason the default `opt-level` for the `release` profile is `3`. -We can choose to override any default setting by adding a different value for -them in *Cargo.toml*. If we wanted to use optimization level 1 in the -development profile, for example, we can add these two lines to our project’s -*Cargo.toml*: +We can override any default setting by adding a different value for it in +*Cargo.toml*. For example, if we want to use optimization level 1 in the +development profile, we can add these two lines to our project’s *Cargo.toml* +file: Filename: Cargo.toml @@ -64,10 +61,10 @@ development profile, for example, we can add these two lines to our project’s opt-level = 1 ``` -This overrides the default setting of `0`. Now when we run `cargo build`, Cargo -will use the defaults for the `dev` profile plus our customization to -`opt-level`. Because we set `opt-level` to `1`, Cargo will apply more -optimizations than the default, but not as many as a release build. +This code overrides the default setting of `0`. Now when we run `cargo` +`build`, Cargo will use the defaults for the `dev` profile plus our +customization to `opt-level`. Because we set `opt-level` to `1`, Cargo will +apply more optimizations than the default, but not as many as a release build. For the full list of configuration options and defaults for each profile, see [Cargo’s documentation](https://doc.rust-lang.org/cargo/). 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 6d8490edb9..4a45ce076b 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 @@ -1,29 +1,30 @@ ## Publishing a Crate to Crates.io -We’ve used packages from crates.io as dependencies of our project, but you can -also share your code for other people to use by publishing your own packages. -Crates.io distributes the source code of your packages, so it primarily hosts -code that’s open source. +We’ve used packages from [crates.io](https://crates.io) as +dependencies of our project, but you can also share your code for other people +to use by publishing your own packages. The crate registry at +[crates.io](https://crates.io) distributes the source code of +your packages, so it primarily hosts code that is open source. Rust and Cargo have features that help make your published package easier for -people to find and use. We’ll talk about some of those features, then cover how -to publish a package. +people to use and to find in the first place. We’ll talk about some of these +features next, and then explain how to publish a package. ### Making Useful Documentation Comments Accurately documenting your packages will help other users know how and when to -use them, so it’s worth spending some time to write documentation. In Chapter -3, we discussed how to comment Rust code with `//`. Rust also has particular -kind of comment for documentation, known conveniently as *documentation +use them, so it’s worth spending time writing documentation. In Chapter 3, we +discussed how to comment Rust code using `//`. Rust also has a particular kind +of comment for documentation, which is known conveniently as *documentation comments*, that will generate HTML documentation. The HTML displays the -contents of documentation comments for public API items, intended for -programmers interested in knowing how to *use* your crate, as opposed to how +contents of documentation comments for public API items intended for +programmers interested in knowing how to *use* your crate as opposed to how your crate is *implemented*. Documentation comments use `///` instead of `//` and support Markdown notation -for formatting the text if you’d like. You place documentation comments just -before the item they are documenting. Listing 14-1 shows documentation comments -for an `add_one` function in a crate named `my_crate`: +for formatting the text if you want to use it. You place documentation comments +just before the item they’re documenting. Listing 14-1 shows documentation +comments for an `add_one` function in a crate named `my_crate`: Filename: src/lib.rs @@ -45,55 +46,55 @@ pub fn add_one(x: i32) -> i32 { Listing 14-1: A documentation comment for a function -Here, we give a description of what the `add_one` function does, then start a -section with the heading “Examplesâ€, and code that demonstrates how to use the -`add_one` function. We can generate the HTML documentation from this -documentation comment by running `cargo doc`. This command runs the `rustdoc` -tool distributed with Rust and puts the generated HTML documentation in the -*target/doc* directory. +Here, we give a description of what the `add_one` function does, start a +section with the heading `Examples`, and then provide code that demonstrates +how to use the `add_one` function. We can generate the HTML documentation from +this documentation comment by running `cargo doc`. This command runs the +`rustdoc` tool distributed with Rust and puts the generated HTML documentation +in the *target/doc* directory. For convenience, running `cargo doc --open` will build the HTML for your current crate’s documentation (as well as the documentation for all of your crate’s dependencies) and open the result in a web browser. Navigate to the -`add_one` function and you’ll see how the text in the documentation comments -gets rendered, shown here in Figure 14-2: +`add_one` function and you’ll see how the text in the documentation comments is +rendered, as shown in Figure 14-1: -Rendered HTML documentation for the `add_one` function of `my_crate` +Rendered HTML documentation for the `add_one` function of `my_crate` -Figure 14-2: HTML documentation for the `add_one` +Figure 14-1: HTML documentation for the `add_one` function #### Commonly Used Sections -We used the `# Examples` markdown heading in Listing 14-1 to create a section -in the HTML with the title “Examplesâ€. Some other sections that crate authors +We used the `# Examples` Markdown heading in Listing 14-1 to create a section +in the HTML with the title “Examples.†Some other sections that crate authors commonly use in their documentation include: -* **Panics**: The scenarios in which this function could `panic!`. Callers of - this function who don’t want their programs to panic should make sure that - they don’t call this function in these situations. -* **Errors**: If this function returns a `Result`, describing the kinds of +* **Panics**: The scenarios in which the function being documented could + `panic!`. Callers of the function who don’t want their programs to panic + should make sure they don’t call the function in these situations. +* **Errors**: If the function returns a `Result`, describing the kinds of errors that might occur and what conditions might cause those errors to be - returned can be helpful to callers so that they can write code to handle the + returned can be helpful to callers so they can write code to handle the different kinds of errors in different ways. -* **Safety**: If this function is `unsafe` to call (we will discuss unsafety in +* **Safety**: If the function is `unsafe` to call (we discuss unsafety in Chapter 19), there should be a section explaining why the function is unsafe - and covering the invariants that this function expects callers to uphold. + and covering the invariants that the function expects callers to uphold. -Most documentation comment sections don’t need all of these sections, but this -is a good list to check to remind you of the kinds of things that people +Most documentation comment sections don’t need all of these sections, but it’s +a good list to check to remind you of the aspects of your code that people calling your code will be interested in knowing about. #### Documentation Comments as Tests -Adding examples in code blocks in your documentation comments is a way to -clearly demonstrate how to use your library, but it has an additional bonus: -running `cargo test` will run the code examples in your documentation as tests! -Nothing is better than documentation with examples. Nothing is worse than -examples that don’t actually work because the code has changed since the -documentation has been written. Try running `cargo test` with the documentation -for the `add_one` function like in Listing 14-1; you should see a section in -the test results like this: +Adding examples in code blocks in your documentation comments can clearly +demonstrate how to use your library, and doing so has an additional bonus: +running `cargo test` will run the code examples in your documentation as +tests! Nothing is better than documentation with examples. But nothing is worse +than examples that don’t work because the code has changed since the +documentation was written. Run `cargo test` with the documentation for the +`add_one` function from Listing 14-1; you should see a section in the test +results like this: ```text Doc-tests my_crate @@ -101,25 +102,25 @@ the test results like this: running 1 test test src/lib.rs - add_one (line 5) ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -Now try changing either the function or the example so that the `assert_eq!` in -the example will panic. Run `cargo test` again, and you’ll see that the doc -tests catch that the example and the code are out of sync from one another! +Now change either the function or the example so the `assert_eq!` in the +example panics. Run `cargo test` again; you’ll see that the doc tests catch +that the example and the code are out of sync from one another! #### Commenting Contained Items -There’s another style of doc comment, `//!`, that adds documentation to the -item that contains the comments, rather than adding documentation to the items -following the comments. These are typically used inside the crate root file +Another style of doc comment, `//!`, adds documentation to the item that +contains the comments rather than adding documentation to the items following +the comments. We typically use these doc comments inside the crate root file (*src/lib.rs* by convention) or inside a module to document the crate or the module as a whole. -For example, if we wanted to add documentation that described the purpose of -the `my_crate` crate that contains the `add_one` function, we can add -documentation comments that start with `//!` to the beginning of *src/lib.rs* -as shown in Listing 14-3: +For example, if we want to add documentation that describes the purpose of the +`my_crate` crate that contains the `add_one` function, we can add documentation +comments that start with `//!` to the beginning of the *src/lib.rs* file, as +shown in Listing 14-2: Filename: src/lib.rs @@ -133,7 +134,7 @@ as shown in Listing 14-3: // --snip-- ``` -Listing 14-3: Documentation for the `my_crate` crate as a +Listing 14-2: Documentation for the `my_crate` crate as a whole Notice there isn’t any code after the last line that begins with `//!`. Because @@ -142,48 +143,48 @@ that contains this comment rather than an item that follows this comment. In this case, the item that contains this comment is the *src/lib.rs* file, which is the crate root. These comments describe the entire crate. -If we run `cargo doc --open`, we’ll see these comments displayed on the front +When we run `cargo doc --open`, these comments will display on the front page of the documentation for `my_crate` above the list of public items in the -crate, as shown in Figure 14-4: +crate, as shown in Figure 14-2: -Rendered HTML documentation with a comment for the crate as a whole +Rendered HTML documentation with a comment for the crate as a whole -Figure 14-4: Rendered documentation for `my_crate` +Figure 14-2: Rendered documentation for `my_crate` including the comment describing the crate as a whole Documentation comments within items are useful for describing crates and -modules especially. Use them to talk about the purpose of the container overall -to help users of your crate understand your organization. +modules especially. Use them to explain the purpose of the container overall to +help your crate users understand your organization. -#### Exporting a Convenient Public API with `pub use` +### Exporting a Convenient Public API with `pub use` -In Chapter 7, we covered how to organize our code into modules with the `mod` -keyword, how to make items public with the `pub` keyword, and how to bring -items into a scope with the `use` keyword. The structure that makes sense to -you while you’re developing a crate may not be very convenient for your users, -however. You may wish to organize your structs in a hierarchy containing -multiple levels, but people that want to use a type you’ve defined deep in the +In Chapter 7, we covered how to organize our code into modules using the `mod` +keyword, how to make items public using the `pub` keyword, and how to bring +items into a scope with the `use` keyword. However, the structure that makes +sense to you while you’re developing a crate might not be very convenient for +your users. You might want to organize your structs in a hierarchy containing +multiple levels, but people who want to use a type you’ve defined deep in the hierarchy might have trouble finding out that those types exist. They might -also be annoyed at having to type `use -my_crate::some_module::another_module::UsefulType;` rather than `use -my_crate::UsefulType;`. +also be annoyed at having to enter `use` +`my_crate::some_module::another_module::UsefulType;` rather than `use` +`my_crate::UsefulType;`. The structure of your public API is a major consideration when publishing a crate. People who use your crate are less familiar with the structure than you -are, and might have trouble finding the pieces they want to use if the module -hierarchy is large. +are and might have difficulty finding the pieces they want to use if your crate +has a large module hierarchy. -The good news is that, if the structure *isn’t* convenient for others to use +The good news is that if the structure *isn’t* convenient for others to use from another library, you don’t have to rearrange your internal organization: -you can choose to re-export items to make a public structure that’s different -to your private structure, using `pub use`. Re-exporting takes a public item in -one location and makes it public in another location as if it was defined in -the other location instead. +instead, you can re-export items to make a public structure that’s different +than your private structure by using `pub use`. Re-exporting takes a public +item in one location and makes it public in another location, as if it was +defined in the other location instead. For example, say we made a library named `art` for modeling artistic concepts. -Within this library is a `kinds` module containing two enums named -`PrimaryColor` and `SecondaryColor` and a `utils` module containing a function -named `mix` as shown in Listing 14-5: +Within this library are two modules: a `kinds` module containing two enums +named `PrimaryColor` and `SecondaryColor`, and a `utils` module containing a +function named `mix`, as shown in Listing 14-3: Filename: src/lib.rs @@ -219,25 +220,25 @@ pub mod utils { } ``` -Listing 14-5: An `art` library with items organized into +Listing 14-3: An `art` library with items organized into `kinds` and `utils` modules -The front page of the documentation for this crate generated by `cargo doc` -would look like Figure 14-6: +Figure 14-3 shows what the front page of the documentation for this crate +generated by `cargo doc` would look like: -Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules +Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules -Figure 14-6: Front page of the documentation for `art` +Figure 14-3: Front page of the documentation for `art` that lists the `kinds` and `utils` modules Note that the `PrimaryColor` and `SecondaryColor` types aren’t listed on the -front page, nor is the `mix` function. We have to click on `kinds` and `utils` -in order to see them. +front page, nor is the `mix` function. We have to click `kinds` and `utils` to +see them. -Another crate depending on this library would need `use` statements that import -the items from `art` including specifying the module structure that’s currently -defined. Listing 14-7 shows an example of a crate that uses the `PrimaryColor` -and `mix` items from the `art` crate: +Another crate that depends on this library would need `use` statements that +import the items from `art`, including specifying the module structure that’s +currently defined. Listing 14-4 shows an example of a crate that uses the +`PrimaryColor` and `mix` items from the `art` crate: Filename: src/main.rs @@ -254,22 +255,23 @@ fn main() { } ``` -Listing 14-7: A crate using the `art` crate’s items with +Listing 14-4: A crate using the `art` crate’s items with its internal structure exported -The author of the code in Listing 14-7 that uses the `art` crate had to figure -out that `PrimaryColor` is in the `kinds` module and `mix` is in the `utils` -module. The module structure of the `art` crate is more relevant to developers -working on the `art` crate than developers using the `art` crate. The internal -structure that organizes parts of the crate into the `kinds` module and the -`utils` module doesn’t add any useful information to someone trying to -understand how to use the `art` crate. The `art` crate’s module structure adds -confusion in having to figure out where to look and inconvenience in having to +The author of the code in Listing 14-4, which uses the `art` crate, had to +figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the +`utils` module. The module structure of the `art` crate is more relevant to +developers working on the `art` crate than developers using the `art` crate. +The internal structure that organizes parts of the crate into the `kinds` +module and the `utils` module doesn’t contain any useful information for +someone trying to understand how to use the `art` crate. Instead, the `art` +crate’s module structure causes confusion because developers have to figure out +where to look, and the structure is inconvenient because developers must specify the module names in the `use` statements. -To remove the internal organization from the public API, we can take the `art` -crate code from Listing 14-5 and add `pub use` statements to re-export the -items at the top level, as shown in Listing 14-8: +To remove the internal organization from the public API, we can modify the +`art` crate code in Listing 14-3 to add `pub use` statements to re-export the +items at the top level, as shown in Listing 14-5: Filename: src/lib.rs @@ -291,21 +293,21 @@ pub mod utils { } ``` -Listing 14-8: Adding `pub use` statements to re-export +Listing 14-5: Adding `pub use` statements to re-export items -The API documentation generated with `cargo doc` for this crate will now list -and link re-exports on the front page as shown in Figure 14-9, which makes -these types easier to find. +The API documentation that `cargo doc` generates for this crate will now list +and link re-exports on the front page, as shown in Figure 14-4, which makes the +`PrimaryColor` and `SecondaryColor` types and the `mix` function easier to find: -Rendered documentation for the `art` crate with the re-exports on the front page +Rendered documentation for the `art` crate with the re-exports on the front page -Figure 14-9: Front page of the documentation for `art` +Figure 14-4: Front page of the documentation for `art` that lists the re-exports -Users of the `art` crate can still see and choose to use the internal structure -as in Listing 14-7, or they can use the more convenient structure from Listing -14-8, as shown in Listing 14-10: +The `art` crate users can still see and use the internal structure from Listing +14-3 as demonstrated in Listing 14-4, or they can use the more convenient +structure in Listing 14-5, as shown in Listing 14-6: Filename: src/main.rs @@ -320,52 +322,54 @@ fn main() { } ``` -Listing 14-10: A program using the re-exported items from +Listing 14-6: A program using the re-exported items from the `art` crate In cases where there are many nested modules, re-exporting the types at the top -level with `pub use` can make a big difference in the experience of people who -use the crate. +level with `pub use` can make a significant difference in the experience of +people who use the crate. Creating a useful public API structure is more of an art than a science, and -you can iterate to find the API that works best for your users. Choosing `pub -use` gives you flexibility in how you structure your crate internally, and -decouples that internal structure with what you present to your users. Take a -look at some of the code of crates you’ve installed to see if their internal -structure differs from their public API. +you can iterate to find the API that works best for your users. Choosing `pub` +`use` gives you flexibility in how you structure your crate internally and +decouples that internal structure with what you present to your users. Look at +some of the code of crates you’ve installed to see if their internal structure +differs from their public API. -### Setting up a Crates.io Account +### Setting Up a Crates.io Account -Before you can publish any crates, you need to create an account on crates.io -and get an API token. To do so, visit the home page at *https://crates.io* and -log in via a GitHub account—the GitHub account is a requirement for now, but -the site may support other ways of creating an account in the future. Once -you’re logged in, visit your account settings at *https://crates.io/me* and -retrieve your API key. Then run the `cargo login` command with your API key, -like this: +Before you can publish any crates, you need to create an account on +[crates.io](https://crates.io) and get an API token. To do so, +visit the home page at [crates.io](https://crates.io) and log in +via a GitHub account: the GitHub account is currently a requirement, but the +site might support other ways of creating an account in the future. Once you’re +logged in, visit your account settings at +[https://crates.io/me/](https://crates.io/me/) and retrieve your +API key. Then run the `cargo` `login` command with your API key, like this: ```text $ cargo login abcdefghijklmnopqrstuvwxyz012345 ``` This command will inform Cargo of your API token and store it locally in -*~/.cargo/credentials*. Note that this token is a *secret* and should not be -shared with anyone else. If it is shared with anyone for any reason, you should -revoke it and generate a new token on Crates.io. +*~/.cargo/credentials*. Note that this token is a *secret*: do not share it +with anyone else. If you do share it with anyone for any reason, you should +revoke it and generate a new token on [crates.io](https://crates.io). ### Before Publishing a New Crate -Now you have an account, and let’s say you already have a crate you want to -publish. Before publishing, you’ll need to add some metadata to your crate by -adding it to the `[package]` section of the crate’s *Cargo.toml*. +Now that you have an account, let’s say you have a crate you want to publish. +Before publishing, you’ll need to add some metadata to your crate by adding it +to the `[package]` section of the crate’s *Cargo.toml* file. -Your crate will first need a unique name. While you’re working on a crate -locally, you may name a crate whatever you’d like. However, crate names on -Crates.io are allocated on a first-come-first-serve basis. Once a crate name is -taken, no one else may publish a crate with that name. Search for the name -you’d like to use on the site to find out if it has been taken. If it hasn’t, -edit the name in *Cargo.toml* under `[package]` to have the name you want to -use for publishing like so: +Your crate will need a unique name. While you’re working on a crate locally, +you can name a crate whatever you’d like. However, crate names on +[crates.io](https://crates.io) are allocated on a first-come, +first-served basis. Once a crate name is taken, no one else can publish a crate +with that name. Search for the name you want to use on the site to find out if +it has been used. If it hasn’t, edit the name in the *Cargo.toml* file under +`[package]` to use the name for publishing, like so: Filename: Cargo.toml @@ -374,8 +378,8 @@ use for publishing like so: name = "guessing_game" ``` -Even if you’ve chosen a unique name, if you try to run `cargo publish` to -publish the crate at this point, you’ll get a warning and then an error: +Even if you’ve chosen a unique name, when you run `cargo publish` to publish +the crate at this point, you’ll get a warning and then an error: ```text $ cargo publish @@ -386,17 +390,17 @@ homepage or repository. error: api errors: missing or empty metadata fields: description, license. ``` -This is because we’re missing some crucial information: a description and -license are required so that people will know what your crate does and under -what terms they may use it. To rectify this error, we need to include this -information in *Cargo.toml*. +The reason is that you’re missing some crucial information: a description and +license are required so people will know what your crate does and under what +terms they can use it. To rectify this error, you need to include this +information in the *Cargo.toml* file. -Make a description that’s just a sentence or two, as it will appear with your -crate in search results and on your crate’s page. For the `license` field, you -need to give a *license identifier value*. The Linux Foundation’s Software -Package Data Exchange (SPDX) at *http://spdx.org/licenses/* lists the -identifiers you can use for this value. For example, to specify that you’ve -licensed your crate using the MIT License, add the `MIT` identifier: +Add a description that is just a sentence or two, because it will appear with +your crate in search results. For the `license` field, you need to give a +*license identifier value*. The Linux Foundation’s Software Package Data +Exchange (SPDX) at *http://spdx.org/licenses/* lists the identifiers you can +use for this value. For example, to specify that you’ve licensed your crate +using the MIT License, add the `MIT` identifier: Filename: Cargo.toml @@ -407,19 +411,19 @@ license = "MIT" ``` If you want to use a license that doesn’t appear in the SPDX, you need to place -the text of that license in a file, include the file in your project, then use -`license-file` to specify the name of that file instead of using the `license` -key. +the text of that license in a file, include the file in your project, and then +use `license-file` to specify the name of that file instead of using the +`license` key. -Guidance on which license is right for your project is out of scope for this -book. Many people in the Rust community choose to license their projects in the -same way as Rust itself, with a dual license of `MIT/Apache-2.0`—this +Guidance on which license is appropriate for your project is beyond the scope +of this book. Many people in the Rust community license their projects in the +same way as Rust by using a dual license of `MIT OR Apache-2.0`, which demonstrates that you can also specify multiple license identifiers separated -by a slash. +by `OR` to have multiple licenses for your project. -So, with a unique name, the version, and author details that `cargo new` added -when you created the crate, your description, and the license you chose added, -the *Cargo.toml* for a project that’s ready to publish might look like this: +With a unique name, the version, the author details that `cargo new` added +when you created the crate, your description, and a license added, the +*Cargo.toml* file for a project that is ready to publish might look like this: Filename: Cargo.toml @@ -429,29 +433,31 @@ name = "guessing_game" version = "0.1.0" authors = ["Your Name "] description = "A fun game where you guess what number the computer has chosen." -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" [dependencies] ``` [Cargo’s documentation](https://doc.rust-lang.org/cargo/) describes other -metadata you can specify to ensure your crate can be discovered and used more +metadata you can specify to ensure others can discover and use your crate more easily! ### Publishing to Crates.io Now that you’ve created an account, saved your API token, chosen a name for your crate, and specified the required metadata, you’re ready to publish! -Publishing a crate uploads a specific version to crates.io for others to use. +Publishing a crate uploads a specific version to +[crates.io](https://crates.io) for others to use. -Take care when publishing a crate, because a publish is *permanent*. The +Be careful when publishing a crate because a publish is *permanent*. The version can never be overwritten, and the code cannot be deleted. One major -goal of Crates.io is to act as a permanent archive of code so that builds of -all projects that depend on crates from Crates.io will continue to work. -Allowing deletion of versions would make fulfilling that goal impossible. -However, there is no limit to the number of versions of a crate you can publish. +goal of [crates.io](https://crates.io) is to act as a permanent +archive of code so that builds of all projects that depend on crates from +[crates.io](https://crates.io) will continue to work. Allowing +version deletions would make fulfilling that goal impossible. However, there is +no limit to the number of crate versions you can publish. -Let’s run the `cargo publish` command again. It should succeed now: +Run the `cargo publish` command again. It should succeed now: ```text $ cargo publish @@ -470,24 +476,24 @@ anyone can easily add your crate as a dependency of their project. ### Publishing a New Version of an Existing Crate When you’ve made changes to your crate and are ready to release a new version, -you change the `version` value specified in your *Cargo.toml* and republish. -Use the [Semantic Versioning rules][semver] to decide what an appropriate next -version number is based on the kinds of changes you’ve made. Then run `cargo -publish` to upload the new version. +you change the `version` value specified in your *Cargo.toml* file and +republish. Use the [Semantic Versioning rules][semver] to decide what an +appropriate next version number is based on the kinds of changes you’ve made. +Then run `cargo publish` to upload the new version. [semver]: http://semver.org/ ### Removing Versions from Crates.io with `cargo yank` -While you can’t remove previous versions of a crate, you can prevent any future -projects from adding them as a new dependency. This is useful when a version of -a crate ends up being broken for one reason or another. For situations such as -this, Cargo supports *yanking* a version of a crate. +Although you can’t remove previous versions of a crate, you can prevent any +future projects from adding them as a new dependency. This is useful when a +crate version is broken for one reason or another. In such situations, Cargo +supports *yanking* a crate version. Yanking a version prevents new projects from starting to depend on that version while allowing all existing projects that depend on it to continue to download and depend on that version. Essentially, a yank means that all projects with a -*Cargo.lock* will not break, while any future *Cargo.lock* files generated will +*Cargo.lock* will not break, and any future *Cargo.lock* files generated will not use the yanked version. To yank a version of a crate, run `cargo yank` and specify which version you @@ -497,13 +503,13 @@ want to yank: $ cargo yank --vers 1.0.1 ``` -You can also undo a yank, and allow projects to start depending on a version -again, by adding `--undo` to the command: +By adding `--undo` to the command, you can also undo a yank and allow projects +to start depending on a version again: ```text $ cargo yank --vers 1.0.1 --undo ``` -A yank *does not* delete any code. The yank feature is not intended for -deleting accidentally uploaded secrets, for example. If that happens, you must +A yank *does not* delete any code. For example, the yank feature is not +intended for deleting accidentally uploaded secrets. If that happens, you must reset those secrets immediately. diff --git a/src/doc/book/second-edition/src/ch14-03-cargo-workspaces.md b/src/doc/book/second-edition/src/ch14-03-cargo-workspaces.md index d1f63f5a60..cc885e2339 100644 --- a/src/doc/book/second-edition/src/ch14-03-cargo-workspaces.md +++ b/src/doc/book/second-edition/src/ch14-03-cargo-workspaces.md @@ -1,86 +1,115 @@ ## Cargo Workspaces -In Chapter 12, we built a package that included both a binary crate and a -library crate. You may find, as your project develops, that the library crate -continues to get bigger and you want to split your package up further into -multiple library crates. In this situation, Cargo has a feature called +In Chapter 12, we built a package that included a binary crate and a library +crate. As your project develops, you might find that the library crate +continues to get bigger and you want to split up your package further into +multiple library crates. In this situation, Cargo offers a feature called *workspaces* that can help manage multiple related packages that are developed in tandem. -A *workspace* is a set of packages that will all share the same *Cargo.lock* -and output directory. Let’s make a project using a workspace, using trivial -code so we can concentrate on the structure of a workspace. We’ll have a binary -that uses two libraries: one library that will provide an `add_one` function -and a second library that will provide an `add_two` function. These three -crates will all be part of the same workspace. We’ll start by creating a new -crate for the binary: +A *workspace* is a set of packages that share the same *Cargo.lock* and output +directory. Let’s make a project using a workspace and use trivial code so we +can concentrate on the structure of the workspace. There are multiple ways to +structure a workspace; we’re going to show a common way. We’ll have a workspace +containing a binary and two libraries. The binary will provide the main +functionality to be used as a command line tool, and it will depend on the two +libraries. One library will provide an `add_one` function, and a second library +will provide an `add_two` function. These three crates will be part of the same +workspace. We’ll start by creating a new directory for the workspace: ```text -$ cargo new --bin adder - Created binary (application) `adder` project -$ cd adder +$ mkdir add +$ cd add ``` -We need to modify the binary package’s *Cargo.toml* and add a `[workspace]` -section to tell Cargo the `adder` package is a workspace. Add this at the -bottom of the file: +In the *add* directory, create a *Cargo.toml* file. This is the *Cargo.toml* +file that configures the entire workspace. It won’t have a `[package]` section +or metadata we’ve seen in other *Cargo.toml* files. Instead, we’ll start with a +`[workspace]` section and add a member to the workspace by specifying the path +*adder*, which is where we’ll put our binary crate: Filename: Cargo.toml ```toml [workspace] + +members = [ + "adder", +] ``` -Like many Cargo features, workspaces support convention over configuration: we -don’t need to add anything more than this to *Cargo.toml* to define our -workspace as long as we follow the convention. +Next, we’ll create the `adder` binary crate by running `cargo new` within the +*add* directory: -### Specifying Workspace Dependencies +```text +$ cargo new --bin adder + Created binary (application) `adder` project +``` -By default, Cargo will include all transitive path dependencies. A *path -dependency* is when any crate, whether in a workspace or not, specifies that it -has a dependency on a crate in a local directory by using the `path` attribute -on the dependency specification in *Cargo.toml*. If a crate has the -`[workspace]` key, or if the crate is itself part of a workspace, and we -specify path dependencies where the paths are subdirectories of the crate’s -directory, those dependent crates will be considered part of the workspace. -Let’s specify in the *Cargo.toml* for the top-level `adder` crate that it will -have a dependency on an `add-one` crate that will be in the `add-one` -subdirectory, by changing *Cargo.toml* to look like this: +At this point, we can build the workspace by running `cargo build`. The files +in your *add* directory should look like this: + +```text +├── Cargo.lock +├── Cargo.toml +├── adder +│ ├── Cargo.toml +│ └── src +│ └── main.rs +└── target +``` + +The workspace has one *target* directory at the top level; the `adder` crate +doesn’t have its own *target* directory. Even if we go into the *adder* +directory and run `cargo build`, the compiled artifacts end up in +*add/target* rather than *add/adder/target*. The crates in a workspace are +meant to depend on each other. If each crate had its own *target* directory, +each crate in the workspace would have to recompile each of the other crates in +the workspace to have the artifacts in its own *target* directory. By sharing +one *target* directory, the crates in the workspace can avoid rebuilding the +other crates in the workspace more than necessary. + +### Creating the Second Crate in the Workspace + +Next, let’s specify another member crate in the workspace. This crate will be +in the *add-one* directory, so change the top-level *Cargo.toml* to have the +*add-one* path as well: Filename: Cargo.toml ```toml -[dependencies] -add-one = { path = "add-one" } +[workspace] + +members = [ + "adder", + "add-one", +] ``` -If we add dependencies to *Cargo.toml* that don’t have a `path` specified, -those dependencies will be normal dependencies that aren’t in this workspace -and are assumed to come from Crates.io. - -### Creating the Second Crate in the Workspace - -Next, while in the `adder` directory, generate an `add-one` crate: +Then generate a new library crate named `add-one`: ```text $ cargo new add-one Created library `add-one` project ``` -Your `adder` directory should now have these directories and files: +Your *add* directory should now have these directories and files: ```text +├── Cargo.lock ├── Cargo.toml ├── add-one -│   ├── Cargo.toml -│   └── src -│   └── lib.rs -└── src - └── main.rs +│ ├── Cargo.toml +│ └── src +│ └── lib.rs +├── adder +│ ├── Cargo.toml +│ └── src +│ └── main.rs +└── target ``` -In *add-one/src/lib.rs*, let’s add an `add_one` function: +In the *add-one/src/lib.rs* file, let’s add an `add_one` function: Filename: add-one/src/lib.rs @@ -90,11 +119,28 @@ pub fn add_one(x: i32) -> i32 { } ``` -Open up *src/main.rs* for `adder` and add an `extern crate` line at the top of -the file to bring the new `add-one` library crate into scope. Then change the -`main` function to call the `add_one` function, as in Listing 14-11: +Now that we have a library crate in the workspace, let’s have the binary crate +`adder` depend on the library crate `add-one`. First, we’ll need to add a path +dependency on `add-one` to *adder/Cargo.toml*: -Filename: src/main.rs +Filename: adder/Cargo.toml + +```toml +[dependencies] + +add-one = { path = "../add-one" } +``` + +Crates in a workspace don’t have to depend on each other, so we still need to +be explicit about the dependency relationships between the crates in a +workspace. + +Next, let’s use the `add_one` function from the `add-one` crate in the `adder` +crate. Open the *adder/src/main.rs* file and add an `extern crate` line at +the top to bring the new `add-one` library crate into scope. Then change the +`main` function to call the `add_one` function, as in Listing 14-7: + +Filename: adder/src/main.rs ```rust,ignore extern crate add_one; @@ -105,56 +151,43 @@ fn main() { } ``` -Listing 14-11: Using the `add-one` library crate from the +Listing 14-7: Using the `add-one` library crate from the `adder` crate -Let’s build the `adder` crate by running `cargo build` in the *adder* directory! +Let’s build the workspace by running `cargo build` in the *add* directory! ```text $ cargo build - Compiling add-one v0.1.0 (file:///projects/adder/add-one) - Compiling adder v0.1.0 (file:///projects/adder) + Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs ``` -Note that this builds both the `adder` crate and the `add-one` crate in -*adder/add-one*. Now your *adder* directory should have these files: +To run the binary crate from the top-level *add* directory, we need to specify +which package in the workspace we want to use by using the `-p` argument and +the package name with `cargo run`: ```text -├── Cargo.lock -├── Cargo.toml -├── add-one -│   ├── Cargo.toml -│   └── src -│   └── lib.rs -├── src -│   └── main.rs -└── target +$ cargo run -p adder + Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/adder` +Hello, world! 10 plus one is 11! ``` -The workspace has one *target* directory at the top level; *add-one* doesn’t -have its own *target* directory. Even if we go into the `add-one` directory and -run `cargo build`, the compiled artifacts end up in *adder/target* rather than -*adder/add-one/target*. The crates in a workspace depend on each other. If each -crate had its own *target* directory, each crate in the workspace would have to -recompile each other crate in the workspace in order to have the artifacts in -its own *target* directory. By sharing one *target* directory, the crates in -the workspace can avoid rebuilding the other crates in the workspace more than -necessary. +This runs the code in *adder/src/main.rs*, which depends on the `add-one` crate. #### Depending on an External Crate in a Workspace -Also notice the workspace only has one *Cargo.lock*, rather than having a -top-level *Cargo.lock* and *add-one/Cargo.lock*. This ensures that all crates -are using the same version of all dependencies. If we add the `rand` crate to -both *Cargo.toml* and *add-one/Cargo.toml*, Cargo will resolve both of those to -one version of `rand` and record that in the one *Cargo.lock*. Making all -crates in the workspace use the same dependencies means the crates in the -workspace will always be compatible with each other. Let’s try this out now. - -Let’s add the `rand` crate to the `[dependencies]` section in -*add-one/Cargo.toml* in order to be able to use the `rand` crate in the -`add-one` crate: +Notice that the workspace has only one *Cargo.lock* file at the top level of +the workspace rather than having a *Cargo.lock* in each crate’s directory. This +ensures that all crates are using the same version of all dependencies. If we +add the `rand` crate to the *adder/Cargo.toml* and *add-one/Cargo.toml* +files, Cargo will resolve both of those to one version of `rand` and record +that in the one *Cargo.lock*. Making all crates in the workspace use the same +dependencies means the crates in the workspace will always be compatible with +each other. Let’s add the `rand` crate to the `[dependencies]` section in the +*add-one/Cargo.toml* file to be able to use the `rand` crate in the `add-one` +crate: Filename: add-one/Cargo.toml @@ -164,9 +197,9 @@ Let’s add the `rand` crate to the `[dependencies]` section in rand = "0.3.14" ``` -We can now add `extern crate rand;` to *add-one/src/lib.rs*, and building the -whole workspace by running `cargo build` in the *adder* directory will bring in -and compile the `rand` crate: +We can now add `extern crate rand;` to the *add-one/src/lib.rs* file, and +building the whole workspace by running `cargo build` in the *add* directory +will bring in and compile the `rand` crate: ```text $ cargo build @@ -174,35 +207,36 @@ $ cargo build Downloading rand v0.3.14 --snip-- Compiling rand v0.3.14 - Compiling add-one v0.1.0 (file:///projects/adder/add-one) - Compiling adder v0.1.0 (file:///projects/adder) + Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs ``` -The top level *Cargo.lock* now contains information about `add-one`’s -dependency on `rand`. However, even though `rand` is used somewhere in the +The top-level *Cargo.lock* now contains information about the dependency of +`add-one` on `rand`. However, even though `rand` is used somewhere in the workspace, we can’t use it in other crates in the workspace unless we add -`rand` to their *Cargo.toml* as well. If we add `extern crate rand;` to -*src/main.rs* for the top level `adder` crate, for example, we’ll get an error: +`rand` to their *Cargo.toml* files as well. For example, if we add `extern +crate rand;` to the *adder/src/main.rs* file for the `adder` crate, we’ll get +an error: ```text $ cargo build - Compiling adder v0.1.0 (file:///projects/adder) -error[E0463]: can't find crate for `rand` - --> src/main.rs:1:1 + Compiling adder v0.1.0 (file:///projects/add/adder) +error: use of unstable library feature 'rand': use `rand` from crates.io (see +issue #27703) + --> adder/src/main.rs:1:1 | 1 | extern crate rand; - | ^^^^^^^^^^^^^^^^^^^ can't find crate ``` -To fix this, edit *Cargo.toml* for the top level `adder` crate and indicate -that `rand` is a dependency for that crate as well. Building the `adder` crate -will add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no -additional copies of `rand` will be downloaded. Cargo has ensured for us that -any crate in the workspace using the `rand` crate will be using the same -version. Using the same version of `rand` across the workspace saves space -since we won’t have multiple copies and ensures that the crates in the -workspace will be compatible with each other. +To fix this, edit the *Cargo.toml* file for the `adder` crate and indicate that +`rand` is a dependency for that crate as well. Building the `adder` crate will +add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no +additional copies of `rand` will be downloaded. Cargo has ensured that any +crate in the workspace using the `rand` crate will be using the same version. +Using the same version of `rand` across the workspace saves space because we +won’t have multiple copies and ensures that the crates in the workspace will be +compatible with each other. #### Adding a Test to a Workspace @@ -227,35 +261,21 @@ mod tests { } ``` -Now run `cargo test` in the top-level *adder* directory: +Now run `cargo test` in the top-level *add* directory: ```text $ cargo test - Compiling adder v0.1.0 (file:///projects/adder) + Compiling add-one v0.1.0 (file:///projects/add/add-one) + Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs - Running target/debug/adder-f0253159197f7841 - -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured -``` - -Wait a second, zero tests? We just added one! If we look at the output, we can -see that `cargo test` in a workspace only runs tests for the top level crate. -To run tests for all of the crates in the workspace, we need to pass the -`--all` flag: - -```text -$ cargo test --all - Finished dev [unoptimized + debuginfo] target(s) in 0.37 secs - Running target/debug/deps/add_one-abcabcabc + Running target/debug/deps/add_one-f0253159197f7841 running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out - Running target/debug/deps/adder-abcabcabc + Running target/debug/deps/adder-f88af9d2cc175a5e running 0 tests @@ -268,10 +288,15 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -When passing `--all`, `cargo test` will run the tests for all of the crates in -the workspace. We can also choose to run tests for one particular crate in a -workspace from the top level directory by using the `-p` flag and specifying -the name of the crate we want to test: +The first section of the output shows that the `it_works` test in the `add-one` +crate passed. The next section shows that 0 tests were found in the `adder` +crate, and then the last section shows 0 documentation tests were found in the +`add-one` crate. Running `cargo test` in a workspace structured like this one +will run the tests for all the crates in the workspace. + +We can also run tests for one particular crate in a workspace from the +top-level directory by using the `-p` flag and specifying the name of the crate +we want to test: ```text $ cargo test -p add-one @@ -293,16 +318,16 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out This output shows `cargo test` only ran the tests for the `add-one` crate and didn’t run the `adder` crate tests. -If you choose to publish the crates in the workspace to crates.io, each crate -in the workspace will get published separately. The `cargo publish` command -does not have an `--all` flag or a `-p` flag, so it is necessary to change to +If you publish the crates in the workspace to *https://crates.io/*, each crate +in the workspace will need to be published separately. The `cargo publish` +command does not have an `--all` flag or a `-p` flag, so you must change to each crate’s directory and run `cargo publish` on each crate in the workspace -in order to publish them. +to publish them. -Now try adding an `add-two` crate to this workspace in a similar way as the -`add-one` crate for some more practice! +For additional practice, add an `add-two` crate to this workspace in a similar +way as the `add-one` crate! -As your project grows, consider using a workspace: smaller components are -easier to understand individually than one big blob of code. Keeping the crates -in a workspace can make coordination among them easier if they work together -and are often changed at the same time. +As your project grows, consider using a workspace: it’s easier to understand +smaller, individual components than one big blob of code. Keeping the crates in +a workspace can make coordination between them easier if they are often changed +at the same time. 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 292766b332..7e68147559 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 @@ -3,21 +3,23 @@ The `cargo install` command allows you to install and use binary crates locally. This isn’t intended to replace system packages; it’s meant to be a convenient way for Rust developers to install tools that others have shared on -crates.io. Only packages that have binary targets can be installed. A binary -target is the runnable program that gets created if the crate has a -*src/main.rs* or another file specified as a binary, as opposed to a library -target that isn’t runnable on its own but is suitable for including within -other programs. Usually, crates have information in the *README* file about -whether a crate is a library, has a binary target, or both. +[crates.io](https://crates.io). You can only install packages +that have binary targets. A binary target is the runnable program that is +created if the crate has a *src/main.rs* file or another file specified as a +binary, as opposed to a library target that isn’t runnable on its own but is +suitable for including within other programs. Usually, crates have information +in the *README* file about whether a crate is a library, has a binary target, +or both. -All binaries from `cargo install` are put into the installation root’s *bin* -folder. If you installed Rust using *rustup.rs* and don’t have any custom -configurations, this will be `$HOME/.cargo/bin`. Ensure that directory is in -your `$PATH` to be able to run programs you’ve gotten through `cargo install`. +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 +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`. -For example, we mentioned in Chapter 12 that there’s a Rust implementation of -the `grep` tool for searching files called `ripgrep`. If we want to install -`ripgrep`, we can run: +For example, in Chapter 12 we mentioned that there’s a Rust implementation of +the `grep` tool called `ripgrep` for searching files. If we want to install +`ripgrep`, we can run the following: ```text $ cargo install ripgrep @@ -31,5 +33,5 @@ Updating registry `https://github.com/rust-lang/crates.io-index` The last line of the output shows the location and the name of the installed binary, which in the case of `ripgrep` is `rg`. As long as the installation -directory is in your `$PATH` as mentioned above, you can then run `rg --help` -and start using a faster, rustier tool for searching files! +directory is in your `$PATH`, as mentioned previously, you can then run `rg` +`--help` and start using a faster, rustier tool for searching files! diff --git a/src/doc/book/second-edition/src/ch14-05-extending-cargo.md b/src/doc/book/second-edition/src/ch14-05-extending-cargo.md index 20da49befa..ba5ade8323 100644 --- a/src/doc/book/second-edition/src/ch14-05-extending-cargo.md +++ b/src/doc/book/second-edition/src/ch14-05-extending-cargo.md @@ -1,16 +1,17 @@ ## Extending Cargo with Custom Commands Cargo is designed so you can extend it with new subcommands without having to -modify Cargo itself. If a binary in your `$PATH` is named `cargo-something`, -you can run it as if it were a Cargo subcommand by running `cargo something`. -Custom commands like this are also listed when you run `cargo --list`. Being -able to `cargo install` extensions and then run them just like the built-in -Cargo tools is a super convenient benefit of Cargo’s design! +modify Cargo. If a binary in your `$PATH` is named `cargo-something`, you can +run it as if it was a Cargo subcommand by running `cargo something`. Custom +commands like this are also listed when you run `cargo --list`. Being able to +use `cargo install` to install extensions and then run them just like the +built-in Cargo tools is a super convenient benefit of Cargo’s design! ## Summary -Sharing code with Cargo and crates.io is part of what makes the Rust ecosystem -useful for many different tasks. Rust’s standard library is small and stable, -but crates are easy to share, use, and improve on a timeline different from the -language itself. Don’t be shy about sharing code that’s useful to you on -Crates.io; it’s likely that it will be useful to someone else as well! +Sharing code with Cargo and [crates.io](https://crates.io) is +part of what makes the Rust ecosystem useful for many different tasks. Rust’s +standard library is small and stable, but crates are easy to share, use, and +improve on a timeline different from the language. Don’t be shy about sharing +code that’s useful to you on [crates.io](https://crates.io); +it’s likely that it will be useful to someone else as well! diff --git a/src/doc/book/second-edition/src/ch15-00-smart-pointers.md b/src/doc/book/second-edition/src/ch15-00-smart-pointers.md index d1417a5f0a..82c8fa1cd1 100644 --- a/src/doc/book/second-edition/src/ch15-00-smart-pointers.md +++ b/src/doc/book/second-edition/src/ch15-00-smart-pointers.md @@ -1,97 +1,56 @@ # Smart Pointers A *pointer* is a general concept for a variable that contains an address in -memory. This address refers to, or “points atâ€, some other data. The most -common kind of pointer in Rust is a *reference*, which we learned about in -Chapter 4. References are indicated by the `&` symbol and borrow the value that -they point to. They don’t have any special abilities other than referring to -data. They also don’t have any overhead, so they’re used the most often. +memory. This address refers to, or “points at,†some other data. The most +common kind of pointer in Rust is a reference, which you learned about in +Chapter 4. References are indicated by the `&` symbol and borrow the value they +point to. They don’t have any special capabilities other than referring to +data. Also, they don’t have any overhead and are the kind of pointer we use +most often. *Smart pointers*, on the other hand, are data structures that act like a -pointer, but they also have additional metadata and capabilities. The concept -of smart pointers isn’t unique to Rust; it originated in C++ and exists in -other languages as well. The different smart pointers defined in Rust’s -standard library provide extra functionality beyond what references provide. -One example that we’ll explore in this chapter is the *reference counting* -smart pointer type, which enables you to have multiple owners of data. The -reference counting smart pointer keeps track of how many owners there are, and -when there aren’t any remaining, the smart pointer takes care of cleaning up -the data. - - - - - - +pointer but also have additional metadata and capabilities. The concept of +smart pointers isn’t unique to Rust: smart pointers originated in C++ and exist +in other languages as well. In Rust, the different smart pointers defined in +the standard library provide extra functionality beyond that provided by +references. One example that we’ll explore in this chapter is the *reference +counting* smart pointer type. This pointer enables you to have multiple owners +of data by keeping track of the number of owners and, when no owners remain, +taking care of cleaning up the data. In Rust, where we have the concept of ownership and borrowing, an additional -difference between references and smart pointers is that references are a kind -of pointer that only borrow data; by contrast, in many cases, smart pointers -*own* the data that they point to. +difference between references and smart pointers is that references are +pointers that only borrow data; in contrast, in many cases, smart pointers +*own* the data they point to. -We’ve actually already encountered a few smart pointers in this book, such as -`String` and `Vec` from Chapter 8, though we didn’t call them smart pointers -at the time. Both these types count as smart pointers because they own some -memory and allow you to manipulate it. They also have metadata (such as their -capacity) and extra capabilities or guarantees (such as `String` ensuring its -data will always be valid UTF-8). +We’ve already encountered a few smart pointers in this book, such as `String` +and `Vec` in Chapter 8, although we didn’t call them smart pointers at the +time. Both these types count as smart pointers because they own some memory and +allow you to manipulate it. They also have metadata (such as their capacity) +and extra capabilities or guarantees (such as with `String` ensuring its data +will always be valid UTF-8). - - - -Smart pointers are usually implemented using structs. The characteristics that -distinguish a smart pointer from an ordinary struct are that smart pointers +Smart pointers are usually implemented using structs. The characteristic that +distinguishes a smart pointer from an ordinary struct is that smart pointers implement the `Deref` and `Drop` traits. The `Deref` trait allows an instance -of the smart pointer struct to behave like a reference so that we can write -code that works with either references or smart pointers. The `Drop` trait -allows us to customize the code that gets run when an instance of the smart -pointer goes out of scope. In this chapter, we’ll be discussing both of those -traits and demonstrating why they’re important to smart pointers. +of the smart pointer struct to behave like a reference so we can write code +that works with either references or smart pointers. The `Drop` trait allows us +to customize the code that is run when an instance of the smart pointer goes +out of scope. In this chapter, we’ll discuss both traits and demonstrate why +they’re important to smart pointers. Given that the smart pointer pattern is a general design pattern used -frequently in Rust, this chapter won’t cover every smart pointer that exists. -Many libraries have their own smart pointers and you can even write some -yourself. We’ll just cover the most common smart pointers from the standard -library: - - - +frequently in Rust, this chapter won’t cover every existing smart pointer. Many +libraries have their own smart pointers, and you can even write your own. We’ll +cover the most common smart pointers in the standard library: * `Box` for allocating values on the heap * `Rc`, a reference counted type that enables multiple ownership * `Ref` and `RefMut`, accessed through `RefCell`, a type that enforces the borrowing rules at runtime instead of compile time - - - -Along the way, we’ll cover the *interior mutability* pattern where an immutable +In addition, we’ll cover the *interior mutability* pattern where an immutable type exposes an API for mutating an interior value. We’ll also discuss -*reference cycles*, how they can leak memory, and how to prevent them. +*reference cycles*: how they can leak memory and how to prevent them. Let’s dive in! diff --git a/src/doc/book/second-edition/src/ch15-01-box.md b/src/doc/book/second-edition/src/ch15-01-box.md index 4b374239d8..d188ff280d 100644 --- a/src/doc/book/second-edition/src/ch15-01-box.md +++ b/src/doc/book/second-edition/src/ch15-01-box.md @@ -2,41 +2,36 @@ The most straightforward smart pointer is a *box*, whose type is written `Box`. Boxes allow you to store data on the heap rather than the stack. What -remains on the stack is the pointer to the heap data. Refer back to Chapter 4 -if you’d like to review the difference between the stack and the heap. +remains on the stack is the pointer to the heap data. Refer to Chapter 4 to +review the difference between the stack and the heap. - - +Boxes don’t have performance overhead, other than storing their data on the +heap instead of on the stack. But they don’t have many extra capabilities +either. You’ll use them most often in these situations: -Boxes don’t have performance overhead other than their data being on the heap -instead of on the stack, but they don’t have a lot of extra abilities either. -They’re most often used in these situations: - -- When you have a type whose size can’t be known at compile time, and you want +* When you have a type whose size can’t be known at compile time, and you want to use a value of that type in a context that needs to know an exact size -- When you have a large amount of data and you want to transfer ownership but +* When you have a large amount of data and you want to transfer ownership but ensure the data won’t be copied when you do so -- When you want to own a value and only care that it’s a type that implements a - particular trait rather than knowing the concrete type itself +* When you want to own a value and only care that it’s a type that implements a + particular trait rather than knowing the concrete type -We’re going to demonstrate the first case in the rest of this section. To -elaborate on the other two situations a bit more: in the second case, +We’ll demonstrate the first situation in this section. But before we do so, +we’ll elaborate on the other two situations a bit more: in the second case, transferring ownership of a large amount of data can take a long time because -the data gets copied around on the stack. To improve performance in this +the data is copied around on the stack. To improve performance in this situation, we can store the large amount of data on the heap in a box. Then, only the small amount of pointer data is copied around on the stack, and the data stays in one place on the heap. The third case is known as a *trait -object*, and Chapter 17 has an entire section devoted just to that topic. So -know that what you learn here will be applied again in Chapter 17! +object*, and Chapter 17 devotes an entire section just to that topic. So what +you learn here you’ll apply again in Chapter 17! ### Using a `Box` to Store Data on the Heap -Before we get into a use case for `Box`, let’s get familiar with the syntax -and how to interact with values stored within a `Box`. +Before we discuss this use case for `Box`, we’ll cover the syntax and how to +interact with values stored within a `Box`. -Listing 15-1 shows how to use a box to store an `i32` on the heap: +Listing 15-1 shows how to use a box to store an `i32` value on the heap: Filename: src/main.rs @@ -53,102 +48,62 @@ box We define the variable `b` to have the value of a `Box` that points to the value `5`, which is allocated on the heap. This program will print `b = 5`; in this case, we can access the data in the box in a similar way as we would if -this data was on the stack. Just like any value that has ownership of data, -when a box goes out of scope like `b` does at the end of `main`, it will be -deallocated. The deallocation happens for both the box (stored on the stack) -and the data it points to (stored on the heap). +this data was on the stack. Just like any owned value, when a box goes out of +scope like `b` does at the end of `main`, it will be deallocated. The +deallocation happens for the box (stored on the stack) and the data it points +to (stored on the heap). Putting a single value on the heap isn’t very useful, so you won’t use boxes by -themselves in the way that Listing 15-1 does very often. Having values like a -single `i32` on the stack, where they’re stored by default is more appropriate -in the majority of cases. Let’s get into a case where boxes allow us to define -types that we wouldn’t be allowed to if we didn’t have boxes. - - - +themselves in this way very often. Having values like a single `i32` on the +stack, where they’re stored by default, is more appropriate in the majority of +situations. Let’s look at a case where boxes allow us to define types that we +wouldn’t be allowed to if we didn’t have boxes. ### Boxes Enable Recursive Types - +At compile time, Rust needs to know how much space a type takes up. One type +whose size can’t be known at compile time is a *recursive type*, where a value +can have as part of itself another value of the same type. Because this nesting +of values could theoretically continue infinitely, Rust doesn’t know how much +space a value of a recursive type needs. However, boxes have a known size, so +by inserting a box in a recursive type definition, we can have recursive types. - - +Let’s explore the *cons list*, which is a data type common in functional +programming languages, as an example of a recursive type. The cons list type +we’ll define is straightforward except for the recursion; therefore, the +concepts in the example we’ll work with will be useful any time you get into +more complex situations involving recursive types. -Rust needs to know at compile time how much space a type takes up. One kind of -type whose size can’t be known at compile time is a *recursive type* where a -value can have as part of itself another value of the same type. This nesting -of values could theoretically continue infinitely, so Rust doesn’t know how -much space a value of a recursive type needs. Boxes have a known size, however, -so by inserting a box in a recursive type definition, we are allowed to have -recursive types. +#### More Information About the Cons List -Let’s explore the *cons list*, a data type common in functional programming -languages, to illustrate this concept. The cons list type we’re going to define -is straightforward except for the recursion, so the concepts in this example -will be useful any time you get into more complex situations involving -recursive types. +A *cons list* is a data structure that comes from the Lisp programming language +and its dialects. In Lisp, the `cons` function (short for “construct functionâ€) +constructs a new pair from its two arguments, which usually are a single value +and another pair. These pairs containing pairs form a list. - - +The cons function concept has made its way into more general functional +programming jargon: “to cons x onto y†informally means to construct a new +container instance by putting the element x at the start of this new container, +followed by the container y. -A cons list is a list where each item in the list contains two things: the -value of the current item and the next item. The last item in the list contains -only a value called `Nil` without a next item. +Each item in a cons list contains two elements: the value of the current item +and the next item. The last item in the list contains only a value called `Nil` +without a next item. A cons list is produced by recursively calling the `cons` +function. The canonical name to denote the base case of the recursion is `Nil`. +Note that this is not the same as the “null†or “nil†concept in Chapter 6, +which is an invalid or absent value. -> #### More Information About the Cons List -> -> A *cons list* is a data structure that comes from the Lisp programming -> language and its dialects. In Lisp, the `cons` function (short for “construct -> functionâ€) constructs a new list from its two arguments, which usually are a -> single value and another list. -> -> The cons function concept has made its way into more general functional -> programming jargon; “to cons x onto y†informally means to construct a new -> container instance by putting the element x at the start of this new -> container, followed by the container y. -> -> A cons list is produced by recursively calling the `cons` function. -> The canonical name to denote the base case of the recursion is `Nil`, which -> announces the end of the list. Note that this is not the same as the “null†-> or “nil†concept from Chapter 6, which is an invalid or absent value. +Although functional programming languages use cons lists frequently, it isn’t a +commonly used data structure in Rust. Most of the time when you have a list of +items in Rust, `Vec` is a better choice to use. Other, more complex +recursive data types *are* useful in various situations, but by starting with +the cons list, we can explore how boxes let us define a recursive data type +without much distraction. -Note that while functional programming languages use cons lists frequently, -this isn’t a commonly used data structure in Rust. Most of the time when you -have a list of items in Rust, `Vec` is a better choice. Other, more complex -recursive data types *are* useful in various situations in Rust, but by -starting with the cons list, we can explore how boxes let us define a recursive -data type without much distraction. - - - - -Listing 15-2 contains an enum definition for a cons list. Note that this -won’t compile quite yet because this is type doesn’t have a known size, which +Listing 15-2 contains an enum definition for a cons list. Note that this code +won’t compile yet because the `List` type doesn’t have a known size, which we’ll demonstrate: - - - Filename: src/main.rs ```rust,ignore @@ -158,22 +113,16 @@ enum List { } ``` -Listing 15-2: The first attempt of defining an enum to +Listing 15-2: The first attempt at defining an enum to represent a cons list data structure of `i32` values -> Note: We’re choosing to implement a cons list that only holds `i32` values -> for the purposes of this example. We could have implemented it using -> generics, as we discussed in Chapter 10, in order to define a cons list type -> that could store values of any type. +> Note: We’re implementing a cons list that only holds `i32` values for the +> purposes of this example. We could have implemented it using generics, as we +> discussed in Chapter 10, to define a cons list type that could store values of +> any type. - - - -Using our cons list type to store the list `1, 2, 3` would look like the code -in Listing 15-3: +Using the `List` type to store the list `1, 2, 3` would look like the code in +Listing 15-3: Filename: src/main.rs @@ -188,16 +137,17 @@ fn main() { Listing 15-3: Using the `List` enum to store the list `1, 2, 3` -The first `Cons` value holds `1` and another `List` value. This `List` -value is another `Cons` value that holds `2` and another `List` value. This +The first `Cons` value holds `1` and another `List` value. This `List` value is +another `Cons` value that holds `2` and another `List` value. This `List` value is one more `Cons` value that holds `3` and a `List` value, which is finally `Nil`, the non-recursive variant that signals the end of the list. -If we try to compile the above code, we get the error shown in Listing 15-4: +If we try to compile the code in Listing 15-3, we get the error shown in +Listing 15-4: ```text error[E0072]: recursive type `List` has infinite size - --> + --> src/main.rs:1:1 | 1 | enum List { | ^^^^^^^^^ recursive type has infinite size @@ -211,22 +161,14 @@ error[E0072]: recursive type `List` has infinite size Listing 15-4: The error we get when attempting to define a recursive enum - - - -The error says this type ‘has infinite size’. The reason is the way we’ve -defined `List` is with a variant that is recursive: it holds another value of -itself directly. This means Rust can’t figure out how much space it needs in -order to store a `List` value. Let’s break this down a bit: first let’s look at -how Rust decides how much space it needs to store a value of a non-recursive +The error shows this type “has infinite size.†The reason is that we’ve defined +`List` with a variant that is recursive: it holds another value of itself +directly. As a result, Rust can’t figure out how much space it needs to store a +`List` value. Let’s break down why we get this error a bit: first, let’s look +at how Rust decides how much space it needs to store a value of a non-recursive type. -### Computing the Size of a Non-Recursive Type +#### Computing the Size of a Non-Recursive Type Recall the `Message` enum we defined in Listing 6-2 when we discussed enum definitions in Chapter 6: @@ -243,9 +185,9 @@ enum Message { To determine how much space to allocate for a `Message` value, Rust goes through each of the variants to see which variant needs the most space. Rust sees that `Message::Quit` doesn’t need any space, `Message::Move` needs enough -space to store two `i32` values, and so forth. Since only one variant will end -up being used, the most space a `Message` value will need is the space it would -take to store the largest of its variants. +space to store two `i32` values, and so forth. Because only one variant will be +used, the most space a `Message` value will need is the space it would take to +store the largest of its variants. Contrast this to what happens when Rust tries to determine how much space a recursive type like the `List` enum in Listing 15-2 needs. The compiler starts @@ -254,41 +196,39 @@ of type `List`. Therefore, `Cons` needs an amount of space equal to the size of an `i32` plus the size of a `List`. To figure out how much memory the `List` type needs, the compiler looks at the variants, starting with the `Cons` variant. The `Cons` variant holds a value of type `i32` and a value of type -`List`, and this continues infinitely, as shown in Figure 15-5. +`List`, and this process continues infinitely, as shown in Figure 15-1: An infinite Cons list -Figure 15-5: An infinite `List` consisting of infinite +Figure 15-1: An infinite `List` consisting of infinite `Cons` variants -### Using `Box` to Get a Recursive Type with a Known Size +#### Using `Box` to Get a Recursive Type with a Known Size Rust can’t figure out how much space to allocate for recursively defined types, -so the compiler gives the error in Listing 15-4. The error does include this -helpful suggestion: +so the compiler gives the error in Listing 15-4. But the error does include +this helpful suggestion: ```text -= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to - make `List` representable + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to + make `List` representable ``` In this suggestion, “indirection†means that instead of storing a value -directly, we’re going to store the value indirectly by storing a pointer to -the value instead. +directly, we’ll change the data structure to store the value indirectly by +storing a pointer to the value instead. Because a `Box` is a pointer, Rust always knows how much space a `Box` needs: a pointer’s size doesn’t change based on the amount of data it’s -pointing to. +pointing to. This means we can put a `Box` inside the `Cons` variant instead +of another `List` value directly. The `Box` will point to the next `List` +value that will be on the heap rather than inside the `Cons` variant. +Conceptually, we still have a list, created with lists “holding†other lists, +but this implementation is now more like the items being next to one another +rather than inside one another. -So we can put a `Box` inside the `Cons` variant instead of another `List` value -directly. The `Box` will point to the next `List` value that will be on the -heap, rather than inside the `Cons` variant. Conceptually, we still have a list -created by lists “holding†other lists, but the way this concept is implemented -is now more like the items being next to one another rather than inside one -another. - -We can change the definition of the `List` enum from Listing 15-2 and the usage -of the `List` from Listing 15-3 to the code in Listing 15-6, which will compile: +We can change the definition of the `List` enum in Listing 15-2 and the usage +of the `List` in Listing 15-3 to the code in Listing 15-5, which will compile: Filename: src/main.rs @@ -308,45 +248,33 @@ fn main() { } ``` -Listing 15-6: Definition of `List` that uses `Box` in +Listing 15-5: Definition of `List` that uses `Box` in order to have a known size The `Cons` variant will need the size of an `i32` plus the space to store the box’s pointer data. The `Nil` variant stores no values, so it needs less space than the `Cons` variant. We now know that any `List` value will take up the size of an `i32` plus the size of a box’s pointer data. By using a box, we’ve -broken the infinite, recursive chain so the compiler is able to figure out the -size it needs to store a `List` value. Figure 15-7 shows what the `Cons` -variant looks like now: +broken the infinite, recursive chain, so the compiler can figure out the size +it needs to store a `List` value. Figure 15-2 shows what the `Cons` variant +looks like now: A finite Cons list -Figure 15-7: A `List` that is not infinitely sized since -`Cons` holds a `Box` - - - +Figure 15-2: A `List` that is not infinitely sized +because `Cons` holds a `Box` Boxes only provide the indirection and heap allocation; they don’t have any -other special abilities like those we’ll see with the other smart pointer +other special capabilities, like those we’ll see with the other smart pointer types. They also don’t have any performance overhead that these special -abilities incur, so they can be useful in cases like the cons list where the +capabilities incur, so they can be useful in cases like the cons list where the indirection is the only feature we need. We’ll look at more use cases for boxes in Chapter 17, too. The `Box` type is a smart pointer because it implements the `Deref` trait, which allows `Box` values to be treated like references. When a `Box` value goes out of scope, the heap data that the box is pointing to is cleaned -up as well because of the `Box` type’s `Drop` trait implementation. Let’s -explore these two traits in more detail; these traits are going to be even more -important to the functionality provided by the other smart pointer types we’ll -be discussing in the rest of this chapter. - - - +up as well because of the `Drop` trait implementation. Let’s explore these two +traits in more detail. These two traits will be even more important to the +functionality provided by the other smart pointer types we’ll discuss in the +rest of this chapter. diff --git a/src/doc/book/second-edition/src/ch15-02-deref.md b/src/doc/book/second-edition/src/ch15-02-deref.md index 914cfa99d3..ecb8fa38f3 100644 --- a/src/doc/book/second-edition/src/ch15-02-deref.md +++ b/src/doc/book/second-edition/src/ch15-02-deref.md @@ -1,57 +1,24 @@ -## Treating Smart Pointers like Regular References with the `Deref` Trait +## Treating Smart Pointers Like Regular References with the `Deref` Trait -Implementing `Deref` trait allows us to customize the behavior of the -*dereference operator* `*`(as opposed to the multiplication or glob operator). -By implementing `Deref` in such a way that a smart pointer can be treated like -a regular reference, we can write code that operates on references and use that -code with smart pointers too. +Implementing the `Deref` trait allows us to customize the behavior of the +*dereference operator*, `*` (as opposed to the multiplication or glob +operator). By implementing `Deref` in such a way that a smart pointer can be +treated like a regular reference, we can write code that operates on references +and use that code with smart pointers too. - - - - - - -Let’s first take a look at how `*` works with regular references, then try and -define our own type like `Box` and see why `*` doesn’t work like a -reference. We’ll explore how implementing the `Deref` trait makes it possible -for smart pointers to work in a similar way as references. Finally, we’ll look -at the *deref coercion* feature of Rust and how that lets us work with either -references or smart pointers. +Let’s first look at how `*` works with regular references, and then try to +define our own type like `Box` and see why `*` doesn’t work like a reference +on our newly defined type. We’ll explore how implementing the `Deref` trait +makes it possible for 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. ### Following the Pointer to the Value with `*` - - - - - - A regular reference is a type of pointer, and one way to think of a pointer is -that it’s an arrow to a value stored somewhere else. In Listing 15-8, let’s -create a reference to an `i32` value then use the dereference operator to -follow the reference to the data: - - - - - - +as an arrow to a value stored somewhere else. In Listing 15-6, we create a +reference to an `i32` value and then use the dereference operator to follow the +reference to the data: Filename: src/main.rs @@ -65,17 +32,17 @@ fn main() { } ``` -Listing 15-8: Using the dereference operator to follow a +Listing 15-6: Using the dereference operator to follow a reference to an `i32` value The variable `x` holds an `i32` value, `5`. We set `y` equal to a reference to `x`. We can assert that `x` is equal to `5`. However, if we want to make an assertion about the value in `y`, we have to use `*y` to follow the reference -to the value that the reference is pointing to (hence *de-reference*). Once we -de-reference `y`, we have access to the integer value `y` is pointing to that -we can compare with `5`. +to the value it’s pointing to (hence *dereference*). Once we dereference `y`, +we have access to the integer value `y` is pointing to that we can compare with +`5`. -If we try to write `assert_eq!(5, y);` instead, we’ll get this compilation +If we tried to write `assert_eq!(5, y);` instead, we would get this compilation error: ```text @@ -90,15 +57,15 @@ not satisfied `{integer}` ``` -Comparing a reference to a number with a number isn’t allowed because they’re -different types. We have to use `*` to follow the reference to the value it’s +Comparing a number and a reference to a number isn’t allowed because they’re +different types. We must use `*` to follow the reference to the value it’s pointing to. ### Using `Box` Like a Reference -We can rewrite the code in Listing 15-8 to use a `Box` instead of a -reference, and the de-reference operator will work the same way as shown in -Listing 15-9: +We can rewrite the code in Listing 15-6 to use a `Box` instead of a +reference, and the dereference operator will work the same way as shown in +Listing 15-7: Filename: src/main.rs @@ -112,26 +79,26 @@ fn main() { } ``` -Listing 15-9: Using the dereference operator on a +Listing 15-7: Using the dereference operator on a `Box` -The only part of Listing 15-8 that we changed was to set `y` to be an instance -of a box pointing to the value in `x` rather than a reference pointing to the -value of `x`. In the last assertion, we can use the dereference operator to -follow the box’s pointer in the same way that we did when `y` was a reference. -Let’s explore what is special about `Box` that enables us to do this by -defining our own box type. +The only difference between Listing 15-7 and Listing 15-6 is that here we set +`y` to be an instance of a box pointing to the value in `x` rather than a +reference pointing to the value of `x`. In the last assertion, we can use the +dereference operator to follow the box’s pointer in the same way that we did +when `y` was a reference. Next, we’ll explore what is special about `Box` +that enables us to use the dereference operator by defining our own box type. ### Defining Our Own Smart Pointer -Let’s build a smart pointer similar to the `Box` type that the standard -library has provided for us, in order to experience that smart pointers don’t -behave like references by default. Then we’ll learn about how to add the -ability to use the dereference operator. +Let’s build a smart pointer similar to the `Box` type provided by the +standard library to experience how smart pointers behave differently to +references by default. Then we’ll look at how to add the ability to use the +dereference operator. -`Box` is ultimately defined as a tuple struct with one element, so Listing -15-10 defines a `MyBox` type in the same way. We’ll also define a `new` -function to match the `new` function defined on `Box`: +The `Box` type is ultimately defined as a tuple struct with one element, so +Listing 15-8 defines a `MyBox` type in the same way. We’ll also define a +`new` function to match the `new` function defined on `Box`: Filename: src/main.rs @@ -145,17 +112,17 @@ impl MyBox { } ``` -Listing 15-10: Defining a `MyBox` type +Listing 15-8: Defining a `MyBox` type -We define a struct named `MyBox` and declare a generic parameter `T`, since we -want our type to be able to hold values of any type. `MyBox` is a tuple struct +We define a struct named `MyBox` and declare a generic parameter `T`, because +we want our type to hold values of any type. The `MyBox` type is a tuple struct with one element of type `T`. The `MyBox::new` function takes one parameter of type `T` and returns a `MyBox` instance that holds the value passed in. -Let’s try adding the code from Listing 15-9 to the code in Listing 15-10 and -changing `main` to use the `MyBox` type we’ve defined instead of `Box`. -The code in Listing 15-11 won’t compile because Rust doesn’t know how to -dereference `MyBox`: +Let’s try adding the `main` function in Listing 15-7 to Listing 15-8 and +changing it to use the `MyBox` type we’ve defined instead of `Box`. The +code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference +`MyBox`: Filename: src/main.rs @@ -169,13 +136,13 @@ fn main() { } ``` -Listing 15-11: Attempting to use `MyBox` in the same -way we were able to use references and `Box` +Listing 15-9: Attempting to use `MyBox` in the same +way we used references and `Box` -The compilation error we get is: +Here’s the resulting compilation error: ```text -error: type `MyBox<{integer}>` cannot be dereferenced +error[E0614]: type `MyBox<{integer}>` cannot be dereferenced --> src/main.rs:14:19 | 14 | assert_eq!(5, *y); @@ -183,16 +150,16 @@ error: type `MyBox<{integer}>` cannot be dereferenced ``` Our `MyBox` type can’t be dereferenced because we haven’t implemented that -ability on our type. To enable dereferencing with the `*` operator, we can +ability on our type. To enable dereferencing with the `*` operator, we implement the `Deref` trait. -### Implementing the `Deref` Trait Defines How To Treat a Type Like a Reference +### Treating a Type Like a Reference by Implementing the `Deref` Trait -As we discussed in Chapter 10, in order to implement a trait, we need to -provide implementations for the trait’s required methods. The `Deref` trait, -provided by the standard library, requires implementing one method named -`deref` that borrows `self` and returns a reference to the inner data. Listing -15-12 contains an implementation of `Deref` to add to the definition of `MyBox`: +As discussed in Chapter 10, to implement a trait, we need to provide +implementations for the trait’s required methods. The `Deref` trait, provided +by the standard library, requires us to implement one method named `deref` that +borrows `self` and returns a reference to the inner data. Listing 15-10 +contains an implementation of `Deref` to add to the definition of `MyBox`: Filename: src/main.rs @@ -209,83 +176,68 @@ impl Deref for MyBox { } ``` -Listing 15-12: Implementing `Deref` on `MyBox` +Listing 15-10: Implementing `Deref` on `MyBox` -The `type Target = T;` syntax defines an associated type for this trait to use. -Associated types are a slightly different way of declaring a generic parameter -that you don’t need to worry about too much for now; we’ll cover it in more -detail in Chapter 19. +The `type Target = T;` syntax defines an associated type for the `Deref` trait +to use. Associated types are a slightly different way of declaring a generic +parameter, but you don’t need to worry about them for now; we’ll cover them in +more detail in Chapter 19. - - - -We filled in the body of the `deref` method with `&self.0` so that `deref` -returns a reference to the value we want to access with the `*` operator. The -`main` function from Listing 15-11 that calls `*` on the `MyBox` value now -compiles and the assertions pass! +We fill in the body of the `deref` method with `&self.0` so `deref` returns a +reference to the value we want to access with the `*` operator. The `main` +function in Listing 15-9 that calls `*` on the `MyBox` value now compiles +and the assertions pass! Without the `Deref` trait, the compiler can only dereference `&` references. -The `Deref` trait’s `deref` method gives the compiler the ability to take a -value of any type that implements `Deref` and call the `deref` method in order -to get a `&` reference that it knows how to dereference. +The `deref` method gives the compiler the ability to take a value of any type +that implements `Deref` and call the `deref` method to get a `&` reference that +it knows how to dereference. -When we typed `*y` in Listing 15-11, what Rust actually ran behind the scenes -was this code: +When we entered `*y` in Listing 15-9, behind the scenes Rust actually ran this +code: ```rust,ignore *(y.deref()) ``` - - - Rust substitutes the `*` operator with a call to the `deref` method and then a -plain dereference so that we don’t have to think about when we have to call the -`deref` method or not. This feature of Rust lets us write code that functions -identically whether we have a regular reference or a type that implements -`Deref`. +plain dereference so as programmers we don’t have to think about whether or not +we need to call the `deref` method. This Rust feature lets us write code that +functions identically whether we have a regular reference or a type that +implements `Deref`. -The reason the `deref` method returns a reference to a value, and why the plain -dereference outside the parentheses in `*(y.deref())` is still necessary, is -because of ownership. If the `deref` method returned the value directly instead -of a reference to the value, the value would be moved out of `self`. We don’t -want to take ownership of the inner value inside `MyBox` in this case and in -most cases where we use the dereference operator. +The reason the `deref` method returns a reference to a value and that the plain +dereference outside the parentheses in `*(y.deref())` is still necessary is due +to the ownership system. If the `deref` method returned the value directly +instead of a reference to the value, the value would be moved out of `self`. We +don’t want to take ownership of the inner value inside `MyBox` in this case +and in most cases where we use the dereference operator. -Note that replacing `*` with a call to the `deref` method and then a call to -`*` happens once, each time we type a `*` in our code. The substitution of `*` -does not recurse infinitely. That’s how we end up with data of type `i32`, -which matches the `5` in the `assert_eq!` in Listing 15-11. +Note that the `*` is replaced with a call to the `deref` method and then a call +to `*` just once, each time we type a `*` in our code. Because the substitution +of `*` does not recurse infinitely, we end up with data of type `i32`, which +matches the `5` in `assert_eq!` in Listing 15-9. ### Implicit Deref Coercions with Functions and Methods - - - *Deref coercion* is a convenience that Rust performs on arguments to functions and methods. Deref coercion converts a reference to a type that implements `Deref` into a reference to a type that `Deref` can convert the original type -into. Deref coercion happens automatically when we pass a reference to a value -of a particular type as an argument to a function or method that doesn’t match -the type of the parameter in the function or method definition, and there’s a -sequence of calls to the `deref` method that will convert the type we provided -into the type that the parameter needs. +into. Deref coercion happens automatically when we pass a reference to a +particular type’s value as an argument to a function or method that doesn’t +match the parameter type in the function or method definition. A sequence of +calls to the `deref` method converts the type we provided into the type the +parameter needs. Deref coercion was added to Rust so that programmers writing function and method calls don’t need to add as many explicit references and dereferences -with `&` and `*`. This feature also lets us write more code that can work for -either references or smart pointers. +with `&` and `*`. The deref coercion feature also lets us write more code that +can work for either references or smart pointers. -To illustrate deref coercion in action, let’s use the `MyBox` type we -defined in Listing 15-10 as well as the implementation of `Deref` that we added -in Listing 15-12. Listing 15-13 shows the definition of a function that has a -string slice parameter: +To see deref coercion in action, let’s use the `MyBox` type we defined in +Listing 15-8 as well as the implementation of `Deref` that we added in Listing +15-10. Listing 15-11 shows the definition of a function that has a string slice +parameter: Filename: src/main.rs @@ -295,13 +247,12 @@ fn hello(name: &str) { } ``` -Listing 15-13: A `hello` function that has the parameter +Listing 15-11: A `hello` function that has the parameter `name` of type `&str` -We can call the `hello` function with a string slice as an argument, like -`hello("Rust");` for example. Deref coercion makes it possible for us to call -`hello` with a reference to a value of type `MyBox`, as shown in -Listing 15-14: +We can call the `hello` function with a string slice as an argument, such as +`hello("Rust");` for example. Deref coercion makes it possible to call `hello` +with a reference to a value of type `MyBox`, as shown in Listing 15-12: Filename: src/main.rs @@ -334,20 +285,20 @@ fn main() { } ``` -Listing 15-14: Calling `hello` with a reference to a -`MyBox`, which works because of deref coercion +Listing 15-12: Calling `hello` with a reference to a +`MyBox` value, which works because of deref coercion Here we’re calling the `hello` function with the argument `&m`, which is a reference to a `MyBox` value. Because we implemented the `Deref` trait -on `MyBox` in Listing 15-12, Rust can turn `&MyBox` into `&String` +on `MyBox` in Listing 15-10, Rust can turn `&MyBox` into `&String` by calling `deref`. The standard library provides an implementation of `Deref` -on `String` that returns a string slice, which we can see in the API -documentation for `Deref`. Rust calls `deref` again to turn the `&String` into -`&str`, which matches the `hello` function’s definition. +on `String` that returns a string slice, which is in the API documentation for +`Deref`. Rust calls `deref` again to turn the `&String` into `&str`, which +matches the `hello` function’s definition. -If Rust didn’t implement deref coercion, in order to call `hello` with a value -of type `&MyBox`, we’d have to write the code in Listing 15-15 instead -of the code in Listing 15-14: +If Rust didn’t implement deref coercion, we would have to write the code in +Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value +of type `&MyBox`: Filename: src/main.rs @@ -380,32 +331,23 @@ fn main() { } ``` -Listing 15-15: The code we’d have to write if Rust didn’t -have deref coercion +Listing 15-13: The code we would have to write if Rust +didn’t have deref coercion -The `(*m)` is dereferencing the `MyBox` into a `String`. Then the `&` -and `[..]` are taking a string slice of the `String` that is equal to the whole -string to match the signature of `hello`. The code without deref coercions is -harder to read, write, and understand with all of these symbols involved. Deref -coercion makes it so that Rust takes care of these conversions for us -automatically. +The `(*m)` dereferences the `MyBox` into a `String`. Then the `&` and +`[..]` take a string slice of the `String` that is equal to the whole string to +match the signature of `hello`. The code without deref coercions is harder to +read, write, and understand with all of these symbols involved. Deref coercion +allows Rust to handle these conversions for us automatically. When the `Deref` trait is defined for the types involved, Rust will analyze the -types and use `Deref::deref` as many times as it needs in order to get a -reference to match the parameter’s type. This is resolved at compile time, so -there is no run-time penalty for taking advantage of deref coercion! +types and use `Deref::deref` as many times as necessary to get a reference to +match the parameter’s type. The number of times that `Deref::deref` needs to be +inserted is resolved at compile time, so there is no runtime penalty for taking +advantage of deref coercion! ### How Deref Coercion Interacts with Mutability - - - Similar to how we use the `Deref` trait to override `*` on immutable references, Rust provides a `DerefMut` trait for overriding `*` on mutable references. @@ -413,32 +355,22 @@ references. Rust does deref coercion when it finds types and trait implementations in three cases: - - +* From `&T` to `&U` when `T: Deref` +* From `&mut T` to `&mut U` when `T: DerefMut` +* From `&mut T` to `&U` when `T: Deref` -* From `&T` to `&U` when `T: Deref`. -* From `&mut T` to `&mut U` when `T: DerefMut`. -* From `&mut T` to `&U` when `T: Deref`. - -The first two cases are the same except for mutability. The first case says +The first two cases are the same except for mutability. The first case states that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can get a `&U` transparently. The second case states that the same deref coercion happens for mutable references. -The last case is trickier: Rust will also coerce a mutable reference to an -immutable one. The reverse is *not* possible though: immutable references will -never coerce to mutable ones. Because of the borrowing rules, if you have a -mutable reference, that mutable reference must be the only reference to that +The third case is trickier: Rust will also coerce a mutable reference to an +immutable one. But the reverse is *not* possible: immutable references will +never coerce to mutable references. Because of the borrowing rules, if you have +a mutable reference, that mutable reference must be the only reference to that data (otherwise, the program wouldn’t compile). Converting one mutable reference to one immutable reference will never break the borrowing rules. Converting an immutable reference to a mutable reference would require that -there was only one immutable reference to that data, and the borrowing rules +there is only one immutable reference to that data, and the borrowing rules don’t guarantee that. Therefore, Rust can’t make the assumption that converting an immutable reference to a mutable reference is possible. - - - diff --git a/src/doc/book/second-edition/src/ch15-03-drop.md b/src/doc/book/second-edition/src/ch15-03-drop.md index 556579c1c5..da3e193fa1 100644 --- a/src/doc/book/second-edition/src/ch15-03-drop.md +++ b/src/doc/book/second-edition/src/ch15-03-drop.md @@ -6,49 +6,27 @@ provide an implementation for the `Drop` trait on any type, and the code we specify can be used to release resources like files or network connections. We’re introducing `Drop` in the context of smart pointers because the functionality of the `Drop` trait is almost always used when implementing a -smart pointer. For example, `Box` customizes `Drop` in order to deallocate -the space on the heap that the box points to. +smart pointer. For example, `Box` customizes `Drop` to deallocate the space +on the heap that the box points to. In some languages, the programmer must call code to free memory or resources every time they finish using an instance of a smart pointer. If they forget, the system might become overloaded and crash. In Rust, we can specify that a particular bit of code should be run whenever a value goes out of scope, and -the compiler will insert this code automatically. - - - - -This means we don’t need to be careful about placing clean up code everywhere -in a program that an instance of a particular type is finished with, but we -still won’t leak resources! +the compiler will insert this code automatically. As a result, we don’t need to +be careful about placing cleanup code everywhere in a program that an instance +of a particular type is finished with, but we still won’t leak resources! We specify the code to run when a value goes out of scope by implementing the `Drop` trait. The `Drop` trait requires us to implement one method named `drop` -that takes a mutable reference to `self`. In order to be able to see when Rust -calls `drop`, let’s implement `drop` with `println!` statements for now. +that takes a mutable reference to `self`. To see when Rust calls `drop`, let’s +implement `drop` with `println!` statements for now. - - - -Listing 15-16 shows a `CustomSmartPointer` struct whose only custom -functionality is that it will print out `Dropping CustomSmartPointer!` when the -instance goes out of scope. This will demonstrate when Rust runs the `drop` +Listing 15-14 shows a `CustomSmartPointer` struct whose only custom +functionality is that it will print `Dropping CustomSmartPointer!` when the +instance goes out of scope. This example demonstrates when Rust runs the `drop` function: - - - Filename: src/main.rs ```rust @@ -69,23 +47,18 @@ fn main() { } ``` -Listing 15-16: A `CustomSmartPointer` struct that -implements the `Drop` trait, where we would put our clean up code. +Listing 15-14: A `CustomSmartPointer` struct that +implements the `Drop` trait where we would put our cleanup code The `Drop` trait is included in the prelude, so we don’t need to import it. We -implement the `Drop` trait on `CustomSmartPointer`, and provide an +implement the `Drop` trait on `CustomSmartPointer` and provide an implementation for the `drop` method that calls `println!`. The body of the -`drop` function is where you’d put any logic that you wanted to run when an -instance of your type goes out of scope. We’re choosing to print out some text -here in order to demonstrate when Rust will call `drop`. +`drop` function is where you would place any logic that you wanted to run when +an instance of your type goes out of scope. We’re printing some text here to +demonstrate when Rust will call `drop`. - - - -In `main`, we create a new instance of `CustomSmartPointer` and then print out -`CustomSmartPointer created.`. At the end of `main`, our instance of +In `main`, we create two instances of `CustomSmartPointer` and then print +`CustomSmartPointers created.`. At the end of `main`, our instance of `CustomSmartPointer` will go out of scope, and Rust will call the code we put in the `drop` method, printing our final message. Note that we didn’t need to call the `drop` method explicitly. @@ -100,34 +73,26 @@ Dropping CustomSmartPointer with data `my stuff`! Rust automatically called `drop` for us when our instance went out of scope, calling the code we specified. Variables are dropped in the reverse order of -the order in which they were created, so `d` was dropped before `c`. This is -just to give you a visual guide to how the drop method works, but usually you -would specify the cleanup code that your type needs to run rather than a print -message. +the order in which they were created, so `d` was dropped before `c`. This +example just gives you a visual guide to how the `drop` method works, but +usually you would specify the cleanup code that your type needs to run rather +than a print message. - - +### Dropping a Value Early with `std::mem::drop` -#### Dropping a Value Early with `std::mem::drop` +Unfortunately, it’s not straightforward to disable the automatic `drop` +functionality. Disabling `drop` isn’t usually necessary; the whole point of the +`Drop` trait is that it’s taken care of automatically. Occasionally, you might +want to clean up a value early. One example is when using smart pointers that +manage locks: you might want to force the `drop` method that releases the lock +to run so other code in the same scope can acquire the lock. Rust doesn’t let +us call the `Drop` trait’s `drop` method manually; instead we have to call the +`std::mem::drop` function provided by the standard library if we want to force +a value to be dropped before the end of its scope. - - - -Rust inserts the call to `drop` automatically when a value goes out of scope, -and it’s not straightforward to disable this functionality. Disabling `drop` -isn’t usually necessary; the whole point of the `Drop` trait is that it’s taken -care of automatically for us. Occasionally you may find that you want to clean -up a value early. One example is when using smart pointers that manage locks; -you may want to force the `drop` method that releases the lock to run so that -other code in the same scope can acquire the lock. First, let’s see what -happens if we try to call the `Drop` trait’s `drop` method ourselves by -modifying the `main` function from Listing 15-16 as shown in Listing 15-17: - - - +Let’s see what happens when we try to call the `Drop` trait’s `drop` method +manually by modifying the `main` function in Listing 15-14, as shown in Listing +15-15: Filename: src/main.rs @@ -140,38 +105,38 @@ fn main() { } ``` -Listing 15-17: Attempting to call the `drop` method from +Listing 15-15: Attempting to call the `drop` method from the `Drop` trait manually to clean up early -If we try to compile this, we’ll get this error: +When we try to compile this code, we’ll get this error: ```text error[E0040]: explicit use of destructor method - --> src/main.rs:15:7 + --> src/main.rs:14:7 | -15 | c.drop(); +14 | c.drop(); | ^^^^ explicit destructor calls not allowed ``` -This error message says we’re not allowed to explicitly call `drop`. The error -message uses the term *destructor*, which is the general programming term for a -function that cleans up an instance. A *destructor* is analogous to a +This error message states that we’re not allowed to explicitly call `drop`. The +error message uses the term *destructor*, which is the general programming term +for a function that cleans up an instance. A *destructor* is analogous to a *constructor* that creates an instance. The `drop` function in Rust is one particular destructor. Rust doesn’t let us call `drop` explicitly because Rust would still -automatically call `drop` on the value at the end of `main`, and this would be -a *double free* error since Rust would be trying to clean up the same value +automatically call `drop` on the value at the end of `main`. This would be a +*double free* error because Rust would be trying to clean up the same value twice. -Because we can’t disable the automatic insertion of `drop` when a value goes -out of scope, and we can’t call the `drop` method explicitly, if we need to -force a value to be cleaned up early, we can use the `std::mem::drop` function. +We can’t disable the automatic insertion of `drop` when a value goes out of +scope, and we can’t call the `drop` method explicitly. So, if we need to force +a value to be cleaned up early, we can use the `std::mem::drop` function. The `std::mem::drop` function is different than the `drop` method in the `Drop` trait. We call it by passing the value we want to force to be dropped early as -an argument. `std::mem::drop` is in the prelude, so we can modify `main` from -Listing 15-16 to call the `drop` function as shown in Listing 15-18: +an argument. The function is in the prelude, so we can modify `main` in Listing +15-14 to call the `drop` function, as shown in Listing 15-16: Filename: src/main.rs @@ -194,7 +159,7 @@ fn main() { } ``` -Listing 15-18: Calling `std::mem::drop` to explicitly +Listing 15-16: Calling `std::mem::drop` to explicitly drop a value before it goes out of scope Running this code will print the following: @@ -205,31 +170,21 @@ Dropping CustomSmartPointer with data `some data`! CustomSmartPointer dropped before the end of main. ``` - - +The text ```Dropping CustomSmartPointer with data `some data`!``` is printed +between the `CustomSmartPointer created.` and `CustomSmartPointer dropped +before the end of main.` text, showing that the `drop` method code is called to +drop `c` at that point. -The ```Dropping CustomSmartPointer with data `some data`!``` is printed between `CustomSmartPointer -created.` and `CustomSmartPointer dropped before the end of main.`, showing -that the `drop` method code is called to drop `c` at that point. - - - - -Code specified in a `Drop` trait implementation can be used in many ways to -make cleanup convenient and safe: we could use it to create our own memory -allocator, for instance! With the `Drop` trait and Rust’s ownership system, you -don’t have to remember to clean up after yourself, Rust takes care of it -automatically. +We can use code specified in a `Drop` trait implementation in many ways to make +cleanup convenient and safe: for instance, we could use it to create our own +memory allocator! With the `Drop` trait and Rust’s ownership system, we don’t +have to remember to clean up because Rust does it automatically. We also don’t have to worry about accidentally cleaning up values still in use because that would cause a compiler error: the ownership system that makes sure -references are always valid will also make sure that `drop` only gets called -once when the value is no longer being used. +references are always valid also ensures that `drop` gets called only once when +the value is no longer being used. -Now that we’ve gone over `Box` and some of the characteristics of smart -pointers, let’s talk about a few other smart pointers defined in the standard +Now that we’ve examined `Box` and some of the characteristics of smart +pointers, let’s look at a few other smart pointers defined in the standard library. diff --git a/src/doc/book/second-edition/src/ch15-04-rc.md b/src/doc/book/second-edition/src/ch15-04-rc.md index 4fe4807e8d..63108932a4 100644 --- a/src/doc/book/second-edition/src/ch15-04-rc.md +++ b/src/doc/book/second-edition/src/ch15-04-rc.md @@ -1,55 +1,52 @@ ## `Rc`, the Reference Counted Smart Pointer In the majority of cases, ownership is clear: you know exactly which variable -owns a given value. However, there are cases when a single value may have -multiple owners. For example, in graph data structures, multiple edges may +owns a given value. However, there are cases when a single value might have +multiple owners. For example, in graph data structures, multiple edges might point to the same node, and that node is conceptually owned by all of the edges that point to it. A node shouldn’t be cleaned up unless it doesn’t have any edges pointing to it. - - +To enable multiple ownership, Rust has a type called `Rc`. Its name is an +abbreviation for *reference counting*, which keeps track of the number of +references to a value to know whether or not a value is still in use. If there +are zero references to a value, the value can be cleaned up without any +references becoming invalid. -In order to enable multiple ownership, Rust has a type called `Rc`. Its name -is an abbreviation for reference counting. *Reference counting* means keeping -track of the number of references to a value in order to know if a value is -still in use or not. If there are zero references to a value, the value can be -cleaned up without any references becoming invalid. - -Imagine it like a TV in a family room. When one person enters to watch TV, they -turn it on. Others can come into the room and watch the TV. When the last -person leaves the room, they turn the TV off because it’s no longer being used. -If someone turns the TV off while others are still watching it, there’d be +Imagine `Rc` as a TV in a family room. When one person enters to watch TV, +they turn it on. Others can come into the room and watch the TV. When the last +person leaves the room, they turn off the TV because it’s no longer being used. +If someone turns off the TV while others are still watching it, there would be uproar from the remaining TV watchers! -`Rc` is used when we want to allocate some data on the heap for multiple -parts of our program to read, and we can’t determine at compile time which part -will finish using the data last. If we did know which part would finish last, -we could just make that the owner of the data and the normal ownership rules -enforced at compile time would kick in. +We use the `Rc` type when we want to allocate some data on the heap for +multiple parts of our program to read, and we can’t determine at compile time +which part will finish using the data last. If we knew which part would finish +last, we could just make that part the data’s owner and the normal ownership +rules enforced at compile time would take effect. -Note that `Rc` is only for use in single-threaded scenarios; Chapter 16 on -concurrency will cover how to do reference counting in multithreaded programs. +Note that `Rc` is only for use in single-threaded scenarios. When we discuss +concurrency in Chapter 16, we’ll cover how to do reference counting in +multithreaded programs. ### Using `Rc` to Share Data -Let’s return to our cons list example from Listing 15-6, as we defined it using -`Box`. This time, we want to create two lists that both share ownership of a -third list, which conceptually will look something like Figure 15-19: +Let’s return to our cons list example in Listing 15-5. Recall that we defined +it using `Box`. This time, we’ll create two lists that both share ownership +of a third list, which conceptually will look similar to Figure 15-3: Two lists that share ownership of a third list -Figure 15-19: Two lists, `b` and `c`, sharing ownership -of a third list, `a` +Figure 15-3: Two lists, `b` and `c`, sharing ownership of +a third list, `a` -We’ll create list `a` that contains 5 and then 10, then make two more lists: -`b` that starts with 3 and `c` that starts with 4. Both `b` and `c` lists will -then continue on to the first `a` list containing 5 and 10. In other words, -both lists will try to share the first list containing 5 and 10. +We’ll create list `a` that contains 5 and then 10. Then we’ll make two more +lists: `b` that starts with 3 and `c` that starts with 4. Both `b` and `c` +lists will then continue on to the first `a` list containing 5 and 10. In other +words, both lists will share the first list containing 5 and 10. -Trying to implement this using our definition of `List` with `Box` won’t -work, as shown in Listing 15-20: +Trying to implement this scenario using our definition of `List` with `Box` +won’t work, as shown in Listing 15-17: Filename: src/main.rs @@ -70,10 +67,10 @@ fn main() { } ``` -Listing 15-20: Demonstrating we’re not allowed to have +Listing 15-17: Demonstrating we’re not allowed to have two lists using `Box` that try to share ownership of a third list -If we compile this, we get this error: +When we compile this code, we get this error: ```text error[E0382]: use of moved value: `a` @@ -84,8 +81,8 @@ error[E0382]: use of moved value: `a` 13 | let c = Cons(4, Box::new(a)); | ^ value used here after move | - = note: move occurs because `a` has type `List`, which does not - implement the `Copy` trait + = note: move occurs because `a` has type `List`, which does not implement + the `Copy` trait ``` The `Cons` variants own the data they hold, so when we create the `b` list, `a` @@ -93,27 +90,22 @@ is moved into `b` and `b` owns `a`. Then, when we try to use `a` again when creating `c`, we’re not allowed to because `a` has been moved. We could change the definition of `Cons` to hold references instead, but then -we’d have to specify lifetime parameters. By specifying lifetime parameters, -we’d be specifying that every element in the list will live at least as long as -the list itself. The borrow checker wouldn’t let us compile `let a = Cons(10, -&Nil);` for example, since the temporary `Nil` value would be dropped before -`a` could take a reference to it. +we would have to specify lifetime parameters. By specifying lifetime +parameters, we would be specifying that every element in the list will live at +least as long as the entire list. The borrow checker wouldn’t let us compile +`let a = Cons(10, &Nil);` for example, because the temporary `Nil` value would +be dropped before `a` could take a reference to it. Instead, we’ll change our definition of `List` to use `Rc` in place of -`Box` as shown here in Listing 15-21. Each `Cons` variant now holds a value -and an `Rc` pointing to a `List`. When we create `b`, instead of taking -ownership of `a`, we clone the `Rc` that `a` is holding, which increases the -number of references from 1 to 2 and lets `a` and `b` share ownership of the -data in that `Rc`. We also clone `a` when creating `c`, which increases the -number of references from 2 to 3. Every time we call `Rc::clone`, the reference -count to the data within the `Rc` is increased, and the data won’t be cleaned -up unless there are zero references to it: - - - +`Box`, as shown in Listing 15-18. Each `Cons` variant will now hold a value +and an `Rc` pointing to a `List`. When we create `b`, instead of taking +ownership of `a`, we’ll clone the `Rc` that `a` is holding, which +increases the number of references from one to two and lets `a` and `b` share +ownership of the data in that `Rc`. We’ll also clone `a` when creating +`c`, which increases the number of references from two to three. Every time we +call `Rc::clone`, the reference count to the data within the `Rc` will +increase, and the data won’t be cleaned up unless there are zero references to +it: Filename: src/main.rs @@ -133,50 +125,38 @@ fn main() { } ``` -Listing 15-21: A definition of `List` that uses +Listing 15-18: A definition of `List` that uses `Rc` -We need to add a `use` statement to bring `Rc` into scope because it’s not in -the prelude. In `main`, we create the list holding 5 and 10 and store it in a -new `Rc` in `a`. Then when we create `b` and `c`, we call the `Rc::clone` -function and pass a reference to the `Rc` in `a` as an argument. +We need to add a `use` statement to bring `Rc` into scope because it’s not +in the prelude. In `main`, we create the list holding 5 and 10 and store it in +a new `Rc` in `a`. Then when we create `b` and `c`, we call the +`Rc::clone` function and pass a reference to the `Rc` in `a` as an +argument. -We could have called `a.clone()` rather than `Rc::clone(&a)`, but Rust -convention is to use `Rc::clone` in this case. The implementation of `Rc::clone` -doesn’t make a deep copy of all the data like most types’ implementations of -`clone` do. `Rc::clone` only increments the reference count, which doesn’t take -very much time. Deep copies of data can take a lot of time, so by using -`Rc::clone` for reference counting, we can visually distinguish between the -deep copy kinds of clones that might have a large impact on runtime performance -and memory usage and the types of clones that increase the reference count that -have a comparatively small impact on runtime performance and don’t allocate new -memory. +We could have called `a.clone()` rather than `Rc::clone(&a)`, but Rust’s +convention is to use `Rc::clone` in this case. The implementation of +`Rc::clone` doesn’t make a deep copy of all the data like most types’ +implementations of `clone` do. The call to `Rc::clone` only increments the +reference count, which doesn’t take much time. Deep copies of data can take a +lot of time. By using `Rc::clone` for reference counting, we can visually +distinguish between the deep copy kinds of clones and the kinds of clones that +increase the reference count. When looking for performance problems in the +code, we only need to consider the deep copy clones and can disregard calls to +`Rc::clone`. ### Cloning an `Rc` Increases the Reference Count -Let’s change our working example from Listing 15-21 so that we can see the -reference counts changing as we create and drop references to the `Rc` in `a`. +Let’s change our working example in Listing 15-18 so we can see the reference +counts changing as we create and drop references to the `Rc` in `a`. - - - -In Listing 15-22, we’ll change `main` so that it has an inner scope around list -`c`, so that we can see how the reference count changes when `c` goes out of -scope. At each point in the program where the reference count changes, we’ll -print out the reference count, which we can get by calling the -`Rc::strong_count` function. We’ll talk about why this function is named -`strong_count` rather than `count` in the section later in this chapter about -preventing reference cycles. - - - +In Listing 15-19, we’ll change `main` so it has an inner scope around list `c`; +then we can see how the reference count changes when `c` goes out of scope. At +each point in the program where the reference count changes, we’ll print the +reference count, which we can get by calling the `Rc::strong_count` function. +This function is named `strong_count` rather than `count` because the `Rc` +type also has a `weak_count`; we’ll see what `weak_count` is used for in the +“Preventing Reference Cycles†section. Filename: src/main.rs @@ -202,9 +182,9 @@ fn main() { } ``` -Listing 15-22: Printing out the reference count +Listing 15-19: Printing the reference count -This will print out: +This code prints the following: ```text count after creating a = 1 @@ -213,28 +193,24 @@ count after creating c = 3 count after c goes out of scope = 2 ``` - - - -We’re able to see that the `Rc` in `a` has an initial reference count of one, +We can see that the `Rc` in `a` has an initial reference count of one; then each time we call `clone`, the count goes up by one. When `c` goes out of scope, the count goes down by one. We don’t have to call a function to decrease the reference count like we have to call `Rc::clone` to increase the reference -count; the implementation of the `Drop` trait decreases the reference count -automatically when an `Rc` value goes out of scope. +count: the implementation of the `Drop` trait decreases the reference count +automatically when an `Rc` value goes out of scope. -What we can’t see from this example is that when `b` and then `a` go out of -scope at the end of `main`, the count is then 0, and the `Rc` is cleaned up -completely at that point. Using `Rc` allows a single value to have multiple -owners, and the count will ensure that the value remains valid as long as any -of the owners still exist. +What we can’t see in this example is that when `b` and then `a` go out of scope +at the end of `main`, the count is then 0, and the `Rc` is cleaned up +completely at that point. Using `Rc` allows a single value to have +multiple owners, and the count ensures that the value remains valid as long as +any of the owners still exist. -`Rc` allows us to share data between multiple parts of our program for -reading only, via immutable references. If `Rc` allowed us to have multiple -mutable references too, we’d be able to violate one of the borrowing rules -that we discussed in Chapter 4: multiple mutable borrows to the same place can -cause data races and inconsistencies. But being able to mutate data is very -useful! In the next section, we’ll discuss the interior mutability pattern and -the `RefCell` type that we can use in conjunction with an `Rc` to work -with this restriction on immutability. +Via immutable references, `Rc` allows us to share data between multiple +parts of our program for reading only. If `Rc` allowed us to have multiple +mutable references too, we might violate one of the borrowing rules discussed +in Chapter 4: multiple mutable borrows to the same place can cause data races +and inconsistencies. But being able to mutate data is very useful! In the next +section, we’ll discuss the interior mutability pattern and the `RefCell` +type that we can use in conjunction with an `Rc` to work with this +immutability restriction. diff --git a/src/doc/book/second-edition/src/ch15-05-interior-mutability.md b/src/doc/book/second-edition/src/ch15-05-interior-mutability.md index 053dc2ec07..600b912b43 100644 --- a/src/doc/book/second-edition/src/ch15-05-interior-mutability.md +++ b/src/doc/book/second-edition/src/ch15-05-interior-mutability.md @@ -1,100 +1,73 @@ ## `RefCell` and the Interior Mutability Pattern - - +*Interior mutability* is a design pattern in Rust that allows you to mutate +data even when there are immutable references to that data: normally, this +action is disallowed by the borrowing rules. To do so, the pattern uses +`unsafe` code inside a data structure to bend Rust’s usual rules that govern +mutation and borrowing. We haven’t yet covered unsafe code; we will in Chapter +19. We can use types that use the interior mutability pattern when we can +ensure that the borrowing rules will be followed at runtime, even though the +compiler can’t guarantee that. The `unsafe` code involved is then wrapped in a +safe API, and the outer type is still immutable. - - - -*Interior mutability* is a design pattern in Rust for allowing you to mutate -data even when there are immutable references to that data, normally disallowed -by the borrowing rules. To do so, the pattern uses `unsafe` code inside a data -structure to bend Rust’s usual rules around mutation and borrowing. We haven’t -yet covered unsafe code; we will in Chapter 19. We can choose to use types that -make use of the interior mutability pattern when we can ensure that the -borrowing rules will be followed at runtime, even though the compiler can’t -ensure that. The `unsafe` code involved is then wrapped in a safe API, and the -outer type is still immutable. - -Let’s explore this by looking at the `RefCell` type that follows the +Let’s explore this concept by looking at the `RefCell` type that follows the interior mutability pattern. ### Enforcing Borrowing Rules at Runtime with `RefCell` Unlike `Rc`, the `RefCell` type represents single ownership over the data it holds. So, what makes `RefCell` different than a type like `Box`? -Let’s recall the borrowing rules we learned in Chapter 4: +Recall the borrowing rules you learned in Chapter 4: -1. At any given time, you can have *either* but not both of: - * One mutable reference. - * Any number of immutable references. -2. References must always be valid. +* At any given time, you can have *either* but not both of the following: one + mutable reference or any number of immutable references. +* References must always be valid. With references and `Box`, the borrowing rules’ invariants are enforced at compile time. With `RefCell`, these invariants are enforced *at runtime*. With references, if you break these rules, you’ll get a compiler error. With -`RefCell`, if you break these rules, you’ll get a `panic!`. +`RefCell`, if you break these rules, your program will `panic!` and exit. - - +The advantages of checking the borrowing rules at compile time are that errors +will be caught sooner in the development process, and there is no impact on +runtime performance because all the analysis is completed beforehand. For those +reasons, checking the borrowing rules at compile time is the best choice in the +majority of cases, which is why this is Rust’s default. -The advantages to checking the borrowing rules at compile time are that errors -will be caught sooner in the development process and there is no impact on -runtime performance since all the analysis is completed beforehand. For those -reasons, checking the borrowing rules at compile time is the best choice for -the majority of cases, which is why this is Rust’s default. - -The advantage to checking the borrowing rules at runtime instead is that +The advantage of checking the borrowing rules at runtime instead is that certain memory safe scenarios are then allowed, whereas they are disallowed by the compile time checks. Static analysis, like the Rust compiler, is inherently conservative. Some properties of code are impossible to detect by analyzing the -code: the most famous example is the Halting Problem, which is out of scope of -this book but an interesting topic to research if you’re interested. - - - +code: the most famous example is the Halting Problem, which is beyond the scope +of this book but is an interesting topic to research. Because some analysis is impossible, if the Rust compiler can’t be sure the -code complies with the ownership rules, it may reject a correct program; in -this way, it is conservative. If Rust were to accept an incorrect program, -users would not be able to trust in the guarantees Rust makes. However, if Rust +code complies with the ownership rules, it might reject a correct program; in +this way, it’s conservative. If Rust accepted an incorrect program, users +wouldn’t be able to trust in the guarantees Rust makes. However, if Rust rejects a correct program, the programmer will be inconvenienced, but nothing -catastrophic can occur. `RefCell` is useful when you yourself are sure that -your code follows the borrowing rules, but the compiler is not able to -understand and guarantee that. +catastrophic can occur. The `RefCell` type is useful when you’re sure your +code follows the borrowing rules, but the compiler is unable to understand and +guarantee that. -Similarly to `Rc`, `RefCell` is only for use in single-threaded scenarios -and will give you a compile time error if you try in a multithreaded context. -We’ll talk about how to get the functionality of `RefCell` in a +Similar to `Rc`, `RefCell` is only for use in single-threaded scenarios +and will give you a compile time error if you try using it in a multithreaded +context. We’ll talk about how to get the functionality of `RefCell` in a multithreaded program in Chapter 16. - - +Here is a recap of the reasons to choose `Box`, `Rc`, or `RefCell`: -To recap the reasons to choose `Box`, `Rc`, or `RefCell`: - -- `Rc` enables multiple owners of the same data; `Box` and `RefCell` +* `Rc` enables multiple owners of the same data; `Box` and `RefCell` have single owners. -- `Box` allows immutable or mutable borrows checked at compile time; `Rc` +* `Box` allows immutable or mutable borrows checked at compile time; `Rc` only allows immutable borrows checked at compile time; `RefCell` allows immutable or mutable borrows checked at runtime. -- Because `RefCell` allows mutable borrows checked at runtime, we can mutate - the value inside the `RefCell` even when the `RefCell` is itself - immutable. +* Because `RefCell` allows mutable borrows checked at runtime, we can mutate + the value inside the `RefCell` even when the `RefCell` is immutable. -The last reason is the *interior mutability* pattern. Let’s look at a case when -interior mutability is useful and discuss how this is possible. +Mutating the value inside an immutable value is the *interior mutability* +pattern. Let’s look at a situation in which interior mutability is useful and +examine how it’s possible. ### Interior Mutability: A Mutable Borrow to an Immutable Value @@ -108,7 +81,7 @@ fn main() { } ``` -If we try to compile this, we’ll get this error: +When we try to compile this code, we’ll get the following error: ```text error[E0596]: cannot borrow immutable local variable `x` as mutable @@ -120,43 +93,42 @@ error[E0596]: cannot borrow immutable local variable `x` as mutable | ^ cannot borrow mutably ``` -However, there are situations where it would be useful for a value to be able -to mutate itself in its methods, but to other code, the value would appear to -be immutable. Code outside the value’s methods would not be able to mutate the -value. `RefCell` is one way to get the ability to have interior mutability. -`RefCell` isn’t getting around the borrowing rules completely, but the -borrow checker in the compiler allows this interior mutability and the -borrowing rules are checked at runtime instead. If we violate the rules, we’ll -get a `panic!` instead of a compiler error. +However, there are situations in which it would be useful for a value to mutate +itself in its methods, but to other code, the value would appear immutable. +Code outside the value’s methods would not be able to mutate the value. Using +`RefCell` is one way to get the ability to have interior mutability. But +`RefCell` doesn’t get around the borrowing rules completely: the borrow +checker in the compiler allows this interior mutability, and the borrowing +rules are checked at runtime instead. If we violate the rules, we’ll get a +`panic!` instead of a compiler error. -Let’s work through a practical example where we can use `RefCell` to make it -possible to mutate an immutable value and see why that’s useful. +Let’s work through a practical example where we can use `RefCell` to mutate +an immutable value and see why that is useful. #### A Use Case for Interior Mutability: Mock Objects -A *test double* is the general programming concept for a type that stands in -the place of another type during testing. *Mock objects* are specific types of -test doubles that record what happens during a test so that we can assert that -the correct actions took place. +A *test double* is the general programming concept for a type used in place of +another type during testing. *Mock objects* are specific types of test doubles +that record what happens during a test so we can assert that the correct +actions took place. -While Rust doesn’t have objects in the exact same sense that other languages -have objects, and Rust doesn’t have mock object functionality built into the -standard library like some other languages do, we can definitely create a -struct that will serve the same purposes as a mock object. +Rust doesn’t have objects in the same sense as other languages have objects, +and Rust doesn’t have mock object functionality built into the standard library +like some other languages do. However, we can definitely create a struct that +will serve the same purposes as a mock object. -Here’s the scenario we’d like to test: we’re creating a library that tracks a -value against a maximum value, and sends messages based on how close to the -maximum value the current value is. This could be used for keeping track of a +Here’s the scenario we’ll test: we’ll create a library that tracks a value +against a maximum value and sends messages based on how close to the maximum +value the current value is. This library could be used for keeping track of a user’s quota for the number of API calls they’re allowed to make, for example. -Our library is only going to provide the functionality of tracking how close to -the maximum a value is, and what the messages should be at what times. -Applications that use our library will be expected to provide the actual -mechanism for sending the messages: the application could choose to put a -message in the application, send an email, send a text message, or something -else. Our library doesn’t need to know about that detail; all it needs is -something that implements a trait we’ll provide called `Messenger`. Listing -15-23 shows our library code: +Our library will only provide the functionality of tracking how close to the +maximum a value is and what the messages should be at what times. Applications +that use our library will be expected to provide the mechanism for sending the +messages: the application could put a message in the application, send an +email, send a text message, or something else. The library doesn’t need to know +that detail. All it needs is something that implements a trait we’ll provide +called `Messenger`. Listing 15-20 shows the library code: Filename: src/lib.rs @@ -197,27 +169,27 @@ impl<'a, T> LimitTracker<'a, T> } ``` -Listing 15-23: A library to keep track of how close to a -maximum value a value is, and warn when the value is at certain levels +Listing 15-20: A library to keep track of how close to a +maximum value a value is and warn when the value is at certain levels -One important part of this code is that the `Messenger` trait has one method, -`send`, that takes an immutable reference to `self` and text of the message. -This is the interface our mock object will need to have. The other important -part is that we want to test the behavior of the `set_value` method on the -`LimitTracker`. We can change what we pass in for the `value` parameter, but -`set_value` doesn’t return anything for us to make assertions on. What we want -to be able to say is that if we create a `LimitTracker` with something that +One important part of this code is that the `Messenger` trait has one method +called `send` that takes an immutable reference to `self` and text of the +message. This is the interface our mock object needs to have. The other +important part is that we want to test the behavior of the `set_value` method +on the `LimitTracker`. We can change what we pass in for the `value` parameter, +but `set_value` doesn’t return anything for us to make assertions on. We want +to be able to say that if we create a `LimitTracker` with something that implements the `Messenger` trait and a particular value for `max`, when we pass -different numbers for `value`, the messenger gets told to send the appropriate +different numbers for `value`, the messenger is told to send the appropriate messages. -What we need is a mock object that, instead of actually sending an email or -text message when we call `send`, will only keep track of the messages it’s -told to send. We can create a new instance of the mock object, create a -`LimitTracker` that uses the mock object, call the `set_value` method on -`LimitTracker`, then check that the mock object has the messages we expect. -Listing 15-24 shows an attempt of implementing a mock object to do just that, -but that the borrow checker won’t allow: +We need a mock object that instead of sending an email or text message when we +call `send` will only keep track of the messages it’s told to send. We can +create a new instance of the mock object, create a `LimitTracker` that uses the +mock object, call the `set_value` method on `LimitTracker`, and then check that +the mock object has the messages we expect. Listing 15-21 shows an attempt of +implementing a mock object to do just that but that the borrow checker won’t +allow: Filename: src/lib.rs @@ -254,36 +226,36 @@ mod tests { } ``` -Listing 15-24: An attempt to implement a `MockMessenger` +Listing 15-21: An attempt to implement a `MockMessenger` that isn’t allowed by the borrow checker This test code defines a `MockMessenger` struct that has a `sent_messages` field with a `Vec` of `String` values to keep track of the messages it’s told -to send. We also defined an associated function `new` to make it convenient to +to send. We also define an associated function `new` to make it convenient to create new `MockMessenger` values that start with an empty list of messages. We -then implement the `Messenger` trait for `MockMessenger` so that we can give a +then implement the `Messenger` trait for `MockMessenger` so we can give a `MockMessenger` to a `LimitTracker`. In the definition of the `send` method, we take the message passed in as a parameter and store it in the `MockMessenger` list of `sent_messages`. In the test, we’re testing what happens when the `LimitTracker` is told to set -`value` to something that’s over 75% of the `max` value. First, we create a new -`MockMessenger`, which will start with an empty list of messages. Then we -create a new `LimitTracker` and give it a reference to the new `MockMessenger` -and a `max` value of 100. We call the `set_value` method on the `LimitTracker` -with a value of 80, which is more than 75% of 100. Then we assert that the list -of messages that the `MockMessenger` is keeping track of should now have one -message in it. +`value` to something that is more than 75 percent of the `max` value. First, we +create a new `MockMessenger`, which will start with an empty list of messages. +Then we create a new `LimitTracker` and give it a reference to the new +`MockMessenger` and a `max` value of 100. We call the `set_value` method on the +`LimitTracker` with a value of 80, which is more than 75 percent of 100. Then +we assert that the list of messages that the `MockMessenger` is keeping track +of should now have one message in it. -There’s one problem with this test, however: +However, there’s one problem with this test, as shown here: ```text error[E0596]: cannot borrow immutable field `self.sent_messages` as mutable - --> src/lib.rs:46:13 + --> src/lib.rs:52:13 | -45 | fn send(&self, message: &str) { +51 | fn send(&self, message: &str) { | ----- use `&mut self` here to make mutable -46 | self.sent_messages.push(String::from(message)); +52 | self.sent_messages.push(String::from(message)); | ^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field ``` @@ -293,10 +265,10 @@ suggestion from the error text to use `&mut self` instead because then the signature of `send` wouldn’t match the signature in the `Messenger` trait definition (feel free to try and see what error message you get). -This is where interior mutability can help! We’re going to store the -`sent_messages` within a `RefCell`, and then the `send` message will be able to -modify `sent_messages` to store the messages we’ve seen. Listing 15-25 shows -what that looks like: +This is a situation in which interior mutability can help! We’ll store the +`sent_messages` within a `RefCell`, and then the `send` message will be +able to modify `sent_messages` to store the messages we’ve seen. Listing 15-22 +shows what that looks like: Filename: src/lib.rs @@ -334,52 +306,48 @@ mod tests { } ``` -Listing 15-25: Using `RefCell` to be able to mutate an -inner value while the outer value is considered immutable +Listing 15-22: Using `RefCell` to mutate an inner +value while the outer value is considered immutable The `sent_messages` field is now of type `RefCell>` instead of -`Vec`. In the `new` function, we create a new `RefCell` instance around -the empty vector. +`Vec`. In the `new` function, we create a new `RefCell>` +instance around the empty vector. For the implementation of the `send` method, the first parameter is still an immutable borrow of `self`, which matches the trait definition. We call -`borrow_mut` on the `RefCell` in `self.sent_messages` to get a mutable -reference to the value inside the `RefCell`, which is the vector. Then we can -call `push` on the mutable reference to the vector in order to keep track of -the messages seen during the test. +`borrow_mut` on the `RefCell>` in `self.sent_messages` to get a +mutable reference to the value inside the `RefCell>`, which is +the vector. Then we can call `push` on the mutable reference to the vector to +keep track of the messages sent during the test. -The last change we have to make is in the assertion: in order to see how many -items are in the inner vector, we call `borrow` on the `RefCell` to get an +The last change we have to make is in the assertion: to see how many items are +in the inner vector, we call `borrow` on the `RefCell>` to get an immutable reference to the vector. -Now that we’ve seen how to use `RefCell`, let’s dig into how it works! +Now that you’ve seen how to use `RefCell`, let’s dig into how it works! #### `RefCell` Keeps Track of Borrows at Runtime -When creating immutable and mutable references we use the `&` and `&mut` +When creating immutable and mutable references, we use the `&` and `&mut` syntax, respectively. With `RefCell`, we use the `borrow` and `borrow_mut` methods, which are part of the safe API that belongs to `RefCell`. The -`borrow` method returns the smart pointer type `Ref`, and `borrow_mut` returns -the smart pointer type `RefMut`. Both types implement `Deref` so we can treat -them like regular references. +`borrow` method returns the smart pointer type `Ref`, and `borrow_mut` +returns the smart pointer type `RefMut`. Both types implement `Deref` so +we can treat them like regular references. - - - -The `RefCell` keeps track of how many `Ref` and `RefMut` smart pointers are -currently active. Every time we call `borrow`, the `RefCell` increases its -count of how many immutable borrows are active. When a `Ref` value goes out of -scope, the count of immutable borrows goes down by one. Just like the compile -time borrowing rules, `RefCell` lets us have many immutable borrows or one -mutable borrow at any point in time. +The `RefCell` keeps track of how many `Ref` and `RefMut` smart +pointers are currently active. Every time we call `borrow`, the `RefCell` +increases its count of how many immutable borrows are active. When a `Ref` +value goes out of scope, the count of immutable borrows goes down by one. Just +like the compile time borrowing rules, `RefCell` lets us have many immutable +borrows or one mutable borrow at any point in time. If we try to violate these rules, rather than getting a compiler error like we would with references, the implementation of `RefCell` will `panic!` at -runtime. Listing 15-26 shows a modification to the implementation of `send` -from Listing 15-25 where we’re deliberately trying to create two mutable -borrows active for the same scope in order to illustrate that `RefCell` -prevents us from doing this at runtime: +runtime. Listing 15-23 shows a modification of the implementation of `send` in +Listing 15-22. We’re deliberately trying to create two mutable borrows active +for the same scope to illustrate that `RefCell` prevents us from doing this +at runtime: Filename: src/lib.rs @@ -395,14 +363,14 @@ impl Messenger for MockMessenger { } ``` -Listing 15-26: Creating two mutable references in the +Listing 15-23: Creating two mutable references in the same scope to see that `RefCell` will panic -We create a variable `one_borrow` for the `RefMut` smart pointer returned from -`borrow_mut`. Then we create another mutable borrow in the same way in the +We create a variable `one_borrow` for the `RefMut` smart pointer returned +from `borrow_mut`. Then we create another mutable borrow in the same way in the variable `two_borrow`. This makes two mutable references in the same scope, -which isn’t allowed. If we run the tests for our library, this code will -compile without any errors, but the test will fail: +which isn’t allowed. When we run the tests for our library, the code in Listing +15-23 will compile without any errors, but the test will fail: ```text ---- tests::it_sends_an_over_75_percent_warning_message stdout ---- @@ -411,37 +379,34 @@ compile without any errors, but the test will fail: note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -We can see that the code panicked with the message `already borrowed: +Notice that the code panicked with the message `already borrowed: BorrowMutError`. This is how `RefCell` handles violations of the borrowing rules at runtime. -Catching borrowing errors at runtime rather than compile time means that we’d -find out that we made a mistake in our code later in the development process-- -and possibly not even until our code was deployed to production. There’s also a -small runtime performance penalty our code will incur as a result of keeping -track of the borrows at runtime rather than compile time. However, using -`RefCell` made it possible for us to write a mock object that can modify itself -to keep track of the messages it has seen while we’re using it in a context -where only immutable values are allowed. We can choose to use `RefCell` -despite its tradeoffs to get more abilities than regular references give us. +Catching borrowing errors at runtime rather than compile time means that we +would find a mistake in our code later in the development process and possibly +not even until our code was deployed to production. Also, our code will incur a +small runtime performance penalty as a result of keeping track of the borrows +at runtime rather than compile time. However, using `RefCell` makes it +possible for us to write a mock object that can modify itself to keep track of +the messages it has seen while we’re using it in a context where only immutable +values are allowed. We can use `RefCell` despite its trade-offs to get more +functionality than regular references give us. ### Having Multiple Owners of Mutable Data by Combining `Rc` and `RefCell` A common way to use `RefCell` is in combination with `Rc`. Recall that `Rc` lets us have multiple owners of some data, but it only gives us immutable access to that data. If we have an `Rc` that holds a `RefCell`, -then we can get a value that can have multiple owners *and* that we can mutate! +we can get a value that can have multiple owners *and* that we can mutate! - - - -For example, recall the cons list example from Listing 15-13 where we used +For example, recall the cons list example in Listing 15-18 where we used `Rc` to let us have multiple lists share ownership of another list. Because -`Rc` only holds immutable values, we aren’t able to change any of the values -in the list once we’ve created them. Let’s add in `RefCell` to get the -ability to change the values in the lists. Listing 15-27 shows that by using a -`RefCell` in the `Cons` definition, we’re allowed to modify the value stored -in all the lists: +`Rc` only holds immutable values, we can’t change any of the values in the +list once we’ve created them. Let’s add in `RefCell` to gain the ability to +change the values in the lists. Listing 15-24 shows that by using a +`RefCell` in the `Cons` definition, we can modify the value stored in all +the lists: Filename: src/main.rs @@ -472,31 +437,27 @@ fn main() { } ``` -Listing 15-27: Using `Rc>` to create a +Listing 15-24: Using `Rc>` to create a `List` that we can mutate -We create a value that’s an instance of `Rc` and store it in a +We create a value that is an instance of `Rc` and store it in a variable named `value` so we can access it directly later. Then we create a `List` in `a` with a `Cons` variant that holds `value`. We need to clone -`value` so that both `a` and `value` have ownership of the inner `5` value, -rather than transferring ownership from `value` to `a` or having `a` borrow -from `value`. +`value` so both `a` and `value` have ownership of the inner `5` value rather +than transferring ownership from `value` to `a` or having `a` borrow from +`value`. - - +We wrap the list `a` in an `Rc` so when we create lists `b` and `c`, they +can both refer to `a`, which is what we did in Listing 15-18. -We wrap the list `a` in an `Rc` so that when we create lists `b` and -`c`, they can both refer to `a`, the same as we did in Listing 15-13. - -Once we have the lists in `a`, `b`, and `c` created, we add 10 to the value in +After we’ve created the lists in `a`, `b`, and `c`, we add 10 to the value in `value`. We do this by calling `borrow_mut` on `value`, which uses the -automatic dereferencing feature we discussed in Chapter 5 (“Where’s the `->` -Operator?â€) to dereference the `Rc` to the inner `RefCell` value. The -`borrow_mut` method returns a `RefMut` smart pointer, and we use the -dereference operator on it and change the inner value. +automatic dereferencing feature we discussed in Chapter 5 (see the section +“Where’s the `->` Operator?â€) to dereference the `Rc` to the inner +`RefCell` value. The `borrow_mut` method returns a `RefMut` smart +pointer, and we use the dereference operator on it and change the inner value. -When we print out `a`, `b`, and `c`, we can see that they all have the modified +When we print `a`, `b`, and `c`, we can see that they all have the modified value of 15 rather than 5: ```text @@ -505,16 +466,16 @@ b after = Cons(RefCell { value: 6 }, Cons(RefCell { value: 15 }, Nil)) c after = Cons(RefCell { value: 10 }, Cons(RefCell { value: 15 }, Nil)) ``` -This is pretty neat! By using `RefCell`, we have an outwardly immutable -`List`, but we can use the methods on `RefCell` that provide access to its -interior mutability so we can modify our data when we need to. The runtime -checks of the borrowing rules protect us from data races, and it’s sometimes -worth trading a bit of speed for this flexibility in our data structures. +This technique is pretty neat! By using `RefCell`, we have an outwardly +immutable `List`. But we can use the methods on `RefCell` that provide +access to its interior mutability so we can modify our data when we need to. +The runtime checks of the borrowing rules protect us from data races, and it’s +sometimes worth trading a bit of speed for this flexibility in our data +structures. -The standard library has other types that provide interior mutability, too, -like `Cell`, which is similar except that instead of giving references to -the inner value, the value is copied in and out of the `Cell`. There’s also -`Mutex`, which offers interior mutability that’s safe to use across threads, -and we’ll be discussing its use in the next chapter on concurrency. Check out -the standard library docs for more details on the differences between these -types. +The standard library has other types that provide interior mutability, such as +`Cell`, which is similar except that instead of giving references to the +inner value, the value is copied in and out of the `Cell`. There’s also +`Mutex`, which offers interior mutability that’s safe to use across threads; +we’ll discuss its use in Chapter 16. Check out the standard library docs for +more details on the differences between these types. diff --git a/src/doc/book/second-edition/src/ch15-06-reference-cycles.md b/src/doc/book/second-edition/src/ch15-06-reference-cycles.md index fc5b4f5365..aeb9d38d62 100644 --- a/src/doc/book/second-edition/src/ch15-06-reference-cycles.md +++ b/src/doc/book/second-edition/src/ch15-06-reference-cycles.md @@ -1,23 +1,27 @@ ## Reference Cycles Can Leak Memory -Rust’s memory safety guarantees make it *difficult* to accidentally create -memory that’s never cleaned up, known as a *memory leak*, but not impossible. -Entirely preventing memory leaks is not one of Rust’s guarantees in the same +Rust’s memory safety guarantees make it *difficult* but not impossible to +accidentally create memory that is never cleaned up (known as a *memory leak*). +Preventing memory leaks entirely is not one of Rust’s guarantees in the same way that disallowing data races at compile time is, meaning memory leaks are -memory safe in Rust. We can see this with `Rc` and `RefCell`: it’s -possible to create references where items refer to each other in a cycle. This -creates memory leaks because the reference count of each item in the cycle will -never reach 0, and the values will never be dropped. +memory safe in Rust. We can see that Rust allows memory leaks by using `Rc` +and `RefCell`: it’s possible to create references where items refer to each +other in a cycle. This creates memory leaks because the reference count of each +item in the cycle will never reach 0, and the values will never be dropped. ### Creating a Reference Cycle -Let’s take a look at how a reference cycle might happen and how to prevent it, +Let’s look at how a reference cycle might happen and how to prevent it, starting with the definition of the `List` enum and a `tail` method in Listing -15-28: +15-25: Filename: src/main.rs -```rust,ignore + + +```rust +# fn main() {} use std::rc::Rc; use std::cell::RefCell; use List::{Cons, Nil}; @@ -38,35 +42,21 @@ impl List { } ``` -Listing 15-28: A cons list definition that holds a -`RefCell` so that we can modify what a `Cons` variant is referring to +Listing 15-25: A cons list definition that holds a +`RefCell` so we can modify what a `Cons` variant is referring to -We’re using another variation of the `List` definition from Listing 15-6. The +We’re using another variation of the `List` definition in Listing 15-5. The second element in the `Cons` variant is now `RefCell>`, meaning that instead of having the ability to modify the `i32` value like we did in Listing -15-19, we want to be able to modify which `List` a `Cons` variant is pointing -to. We’ve also added a `tail` method to make it convenient for us to access the -second item, if we have a `Cons` variant. +15-24, we want to modify which `List` a `Cons` variant is pointing to. We’re +also adding a `tail` method to make it convenient for us to access the second +item if we have a `Cons` variant. - - - -In listing 15-29, we’re adding a `main` function that uses the definitions from -Listing 15-28. This code creates a list in `a`, a list in `b` that points to +In Listing 15-26, we’re adding a `main` function that uses the definitions in +Listing 15-25. This code creates a list in `a` and a list in `b` that points to the list in `a`, and then modifies the list in `a` to point to `b`, which creates a reference cycle. There are `println!` statements along the way to -show what the reference counts are at various points in this process. - - - +show what the reference counts are at various points in this process: Filename: src/main.rs @@ -101,7 +91,7 @@ fn main() { println!("b initial rc count = {}", Rc::strong_count(&b)); println!("b next item = {:?}", b.tail()); - if let Some(ref link) = a.tail() { + if let Some(link) = a.tail() { *link.borrow_mut() = Rc::clone(&b); } @@ -114,22 +104,22 @@ fn main() { } ``` -Listing 15-29: Creating a reference cycle of two `List` +Listing 15-26: Creating a reference cycle of two `List` values pointing to each other -We create an `Rc` instance holding a `List` value in the variable `a` with an -initial list of `5, Nil`. We then create an `Rc` instance holding another -`List` value in the variable `b` that contains the value 10, then points to the -list in `a`. +We create an `Rc` instance holding a `List` value in the variable `a` +with an initial list of `5, Nil`. We then create an `Rc` instance +holding another `List` value in the variable `b` that contains the value 10 and +then points to the list in `a`. -Finally, we modify `a` so that it points to `b` instead of `Nil`, which creates -a cycle. We do that by using the `tail` method to get a reference to the -`RefCell` in `a`, which we put in the variable `link`. Then we use the -`borrow_mut` method on the `RefCell` to change the value inside from an `Rc` -that holds a `Nil` value to the `Rc` in `b`. +We modify `a` so it points to `b` instead of `Nil`, which creates a cycle. We +do that by using the `tail` method to get a reference to the +`RefCell>` in `a`, which we put in the variable `link`. Then we use +the `borrow_mut` method on the `RefCell>` to change the value inside +from an `Rc` that holds a `Nil` value to the `Rc` in `b`. -If we run this code, keeping the last `println!` commented out for the moment, -we’ll get this output: +When we run this code, keeping the last `println!` commented out for the +moment, we’ll get this output: ```text a initial rc count = 1 @@ -141,118 +131,76 @@ b rc count after changing a = 2 a rc count after changing a = 2 ``` -We can see that the reference count of the `Rc` instances in both `a` and `b` -are 2 after we change the list in `a` to point to `b`. At the end of `main`, -Rust will try and drop `b` first, which will decrease the count in each of the -`Rc` instances in `a` and `b` by one. +The reference count of the `Rc` instances in both `a` and `b` are 2 +after we change the list in `a` to point to `b`. At the end of `main`, Rust +will try to drop `b` first, which will decrease the count in each of the +`Rc` instances in `a` and `b` by one. - - - - - - -However, because `a` is still referencing the `Rc` that was in `b`, that `Rc` -has a count of 1 rather than 0, so the memory the `Rc` has on the heap won’t be -dropped. The memory will just sit there with a count of one, forever. - -To visualize this, we’ve created a reference cycle that looks like Figure 15-30: +However, because `a` is still referencing the `Rc` that was in `b`, +that `Rc` has a count of 1 rather than 0, so the memory the +`Rc` has on the heap won’t be dropped. The memory will just sit there +with a count of one, forever. To visualize this reference cycle, we’ve created +a diagram in Figure 15-4: Reference cycle of lists -Figure 15-30: A reference cycle of lists `a` and `b` +Figure 15-4: A reference cycle of lists `a` and `b` pointing to each other -If you uncomment the last `println!` and run the program, Rust will try and -print this cycle out with `a` pointing to `b` pointing to `a` and so forth -until it overflows the stack. +If you uncomment the last `println!` and run the program, Rust will try to +print this cycle with `a` pointing to `b` pointing to `a` and so forth until it +overflows the stack. - - - -In this specific case, right after we create the reference cycle, the program -ends. The consequences of this cycle aren’t so dire. If a more complex program +In this case, right after we create the reference cycle, the program ends. The +consequences of this cycle aren’t very dire. If a more complex program allocates lots of memory in a cycle and holds onto it for a long time, the -program would be using more memory than it needs, and might overwhelm the -system and cause it to run out of available memory. +program would use more memory than it needs and might overwhelm the system, +causing it to run out of available memory. Creating reference cycles is not easily done, but it’s not impossible either. If you have `RefCell` values that contain `Rc` values or similar nested -combinations of types with interior mutability and reference counting, be aware -that you have to ensure you don’t create cycles yourself; you can’t rely on -Rust to catch them. Creating a reference cycle would be a logic bug in your -program that you should use automated tests, code reviews, and other software -development practices to minimize. +combinations of types with interior mutability and reference counting, you must +ensure that you don’t create cycles; you can’t rely on Rust to catch them. +Creating a reference cycle would be a logic bug in your program that you should +use automated tests, code reviews, and other software development practices to +minimize. - - - -Another solution is reorganizing your data structures so that some references -express ownership and some references don’t. In this way, we can have cycles -made up of some ownership relationships and some non-ownership relationships, -and only the ownership relationships affect whether a value may be dropped or -not. In Listing 15-28, we always want `Cons` variants to own their list, so -reorganizing the data structure isn’t possible. Let’s look at an example using -graphs made up of parent nodes and child nodes to see when non-ownership -relationships are an appropriate way to prevent reference cycles. +Another solution for avoiding reference cycles is reorganizing your data +structures so that some references express ownership and some references don’t. +As a result, you can have cycles made up of some ownership relationships and +some non-ownership relationships, and only the ownership relationships affect +whether or not a value can be dropped. In Listing 15-25, we always want `Cons` +variants to own their list, so reorganizing the data structure isn’t possible. +Let’s look at an example using graphs made up of parent nodes and child nodes +to see when non-ownership relationships are an appropriate way to prevent +reference cycles. ### Preventing Reference Cycles: Turn an `Rc` into a `Weak` -So far, we’ve shown how calling `Rc::clone` increases the `strong_count` of an -`Rc` instance, and that an `Rc` instance is only cleaned up if its -`strong_count` is 0. We can also create a *weak reference* to the value within -an `Rc` instance by calling `Rc::downgrade` and passing a reference to the -`Rc`. When we call `Rc::downgrade`, we get a smart pointer of type `Weak`. -Instead of increasing the `strong_count` in the `Rc` instance by one, calling -`Rc::downgrade` increases the `weak_count` by one. The `Rc` type uses -`weak_count` to keep track of how many `Weak` references exist, similarly to -`strong_count`. The difference is the `weak_count` does not need to be 0 in -order for the `Rc` instance to be cleaned up. +So far, we’ve demonstrated that calling `Rc::clone` increases the +`strong_count` of an `Rc` instance, and an `Rc` instance is only +cleaned up if its `strong_count` is 0. We can also create a *weak reference* to +the value within an `Rc` instance by calling `Rc::downgrade` and passing a +reference to the `Rc`. When we call `Rc::downgrade`, we get a smart +pointer of type `Weak`. Instead of increasing the `strong_count` in the +`Rc` instance by one, calling `Rc::downgrade` increases the `weak_count` +by one. The `Rc` type uses `weak_count` to keep track of how many +`Weak` references exist, similar to `strong_count`. The difference is the +`weak_count` doesn’t need to be 0 for the `Rc` instance to be cleaned up. - - - -Strong references are how we can share ownership of an `Rc` instance. Weak +Strong references are how we can share ownership of an `Rc` instance. Weak references don’t express an ownership relationship. They won’t cause a -reference cycle since any cycle involving some weak references will be broken +reference cycle because any cycle involving some weak references will be broken once the strong reference count of values involved is 0. - - - -Because the value that `Weak` references might have been dropped, in order -to do anything with the value that a `Weak` is pointing to, we have to check -to make sure the value is still around. We do this by calling the `upgrade` -method on a `Weak` instance, which will return an `Option>`. We’ll get -a result of `Some` if the `Rc` value has not been dropped yet, and `None` if -the `Rc` value has been dropped. Because `upgrade` returns an `Option`, we can -be sure that Rust will handle both the `Some` case and the `None` case, and -there won’t be an invalid pointer. +Because the value that `Weak` references might have been dropped, to do +anything with the value that a `Weak` is pointing to, we must make sure the +value still exists. We do this by calling the `upgrade` method on a `Weak` +instance, which will return an `Option>`. We’ll get a result of `Some` if +the `Rc` value has not been dropped yet and a result of `None` if the +`Rc` value has been dropped. Because `upgrade` returns an `Option`, Rust +will ensure that we handle the `Some` case and the `None` case, and there won’t +be an invalid pointer. As an example, rather than using a list whose items know only about the next item, we’ll create a tree whose items know about their children items *and* @@ -260,8 +208,9 @@ their parent items. #### Creating a Tree Data Structure: a `Node` with Child Nodes -To start building this tree, we’ll create a struct named `Node` that holds its -own `i32` value as well as references to its children `Node` values: +To start, we’ll build a tree with nodes that know about their child nodes. +We’ll create a struct named `Node` that holds its own `i32` value as well as +references to its children `Node` values: Filename: src/main.rs @@ -276,15 +225,15 @@ struct Node { } ``` -We want a `Node` to own its children, and we want to be able to share that -ownership with variables so we can access each `Node` in the tree directly. To -do this, we define the `Vec` items to be values of type `Rc`. We also -want to be able to modify which nodes are children of another node, so we have -a `RefCell` in `children` around the `Vec`. +We want a `Node` to own its children, and we want to share that ownership with +variables so we can access each `Node` in the tree directly. To do this, we +define the `Vec` items to be values of type `Rc`. We also want to +modify which nodes are children of another node, so we have a `RefCell` in +`children` around the `Vec>`. -Next, let’s use our struct definition and create one `Node` instance named +Next, we’ll use our struct definition and create one `Node` instance named `leaf` with the value 3 and no children, and another instance named `branch` -with the value 5 and `leaf` as one of its children, as shown in Listing 15-31: +with the value 5 and `leaf` as one of its children, as shown in Listing 15-27: Filename: src/main.rs @@ -311,36 +260,33 @@ fn main() { } ``` -Listing 15-31: Creating a `leaf` node with no children +Listing 15-27: Creating a `leaf` node with no children and a `branch` node with `leaf` as one of its children -We clone the `Rc` in `leaf` and store that in `branch`, meaning the `Node` in -`leaf` now has two owners: `leaf` and `branch`. We can get from `branch` to -`leaf` through `branch.children`, but there’s no way to get from `leaf` to -`branch`. `leaf` has no reference to `branch` and doesn’t know they are -related. We’d like `leaf` to know that `branch` is its parent. +We clone the `Rc` in `leaf` and store that in `branch`, meaning the +`Node` in `leaf` now has two owners: `leaf` and `branch`. We can get from +`branch` to `leaf` through `branch.children`, but there’s no way to get from +`leaf` to `branch`. The reason is that `leaf` has no reference to `branch` and +doesn’t know they’re related. We want `leaf` to know that `branch` is its +parent. We’ll do that next. -#### Adding a Reference from a Child to its Parent +#### Adding a Reference from a Child to Its Parent To make the child node aware of its parent, we need to add a `parent` field to our `Node` struct definition. The trouble is in deciding what the type of `parent` should be. We know it can’t contain an `Rc` because that would -create a reference cycle, with `leaf.parent` pointing to `branch` and +create a reference cycle with `leaf.parent` pointing to `branch` and `branch.children` pointing to `leaf`, which would cause their `strong_count` -values to never be zero. +values to never be 0. Thinking about the relationships another way, a parent node should own its children: if a parent node is dropped, its child nodes should be dropped as well. However, a child should not own its parent: if we drop a child node, the parent should still exist. This is a case for weak references! -So instead of `Rc`, we’ll make the type of `parent` use `Weak`, specifically -a `RefCell>`. Now our `Node` struct definition looks like this: - - - +So instead of `Rc`, we’ll make the type of `parent` use `Weak`, +specifically a `RefCell>`. Now our `Node` struct definition looks +like this: Filename: src/main.rs @@ -356,21 +302,9 @@ struct Node { } ``` - - - -This way, a node will be able to refer to its parent node, but does not own its -parent. In Listing 15-32, let’s update `main` to use this new definition so -that the `leaf` node will have a way to refer to its parent, `branch`: - - - +Now a node will be able to refer to its parent node but doesn’t own its parent. +In Listing 15-28, we update `main` to use this new definition so the `leaf` +node will have a way to refer to its parent, `branch`: Filename: src/main.rs @@ -406,45 +340,34 @@ fn main() { } ``` -Listing 15-32: A `leaf` node with a `Weak` reference to -its parent node, `branch` - - +Listing 15-28: A `leaf` node with a `Weak` reference to +its parent node `branch` Creating the `leaf` node looks similar to how creating the `leaf` node looked -in Listing 15-31, with the exception of the `parent` field: `leaf` starts out -without a parent, so we create a new, empty `Weak` reference instance. +in Listing 15-27 with the exception of the `parent` field: `leaf` starts out +without a parent, so we create a new, empty `Weak` reference instance. At this point, when we try to get a reference to the parent of `leaf` by using the `upgrade` method, we get a `None` value. We see this in the output from the -first `println!`: +first `println!` statement: ```text leaf parent = None ``` - - +When we create the `branch` node, it will also have a new `Weak` +reference in the `parent` field, because `branch` doesn’t have a parent node. +We still have `leaf` as one of the children of `branch`. Once we have the +`Node` instance in `branch`, we can modify `leaf` to give it a `Weak` +reference to its parent. We use the `borrow_mut` method on the +`RefCell>` in the `parent` field of `leaf`, and then we use the +`Rc::downgrade` function to create a `Weak` reference to `branch` from +the `Rc` in `branch.` -When we create the `branch` node, it will also have a new `Weak` reference, -since `branch` does not have a parent node. We still have `leaf` as one of the -children of `branch`. Once we have the `Node` instance in `branch`, we can -modify `leaf` to give it a `Weak` reference to its parent. We use the -`borrow_mut` method on the `RefCell` in the `parent` field of `leaf`, then we -use the `Rc::downgrade` function to create a `Weak` reference to `branch` from -the `Rc` in `branch.` - - - - -When we print out the parent of `leaf` again, this time we’ll get a `Some` -variant holding `branch`: `leaf` can now access its parent! When we print out -`leaf`, we also avoid the cycle that eventually ended in a stack overflow like -we had in Listing 15-29: the `Weak` references are printed as `(Weak)`: +When we print the parent of `leaf` again, this time we’ll get a `Some` variant +holding `branch`: now `leaf` can access its parent! When we print `leaf`, we +also avoid the cycle that eventually ended in a stack overflow like we had in +Listing 15-26: the `Weak` references are printed as `(Weak)`: ```text leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) }, @@ -458,15 +381,25 @@ cycle. We can also tell this by looking at the values we get from calling #### Visualizing Changes to `strong_count` and `weak_count` -Let’s look at how the `strong_count` and `weak_count` values of the `Rc` +Let’s look at how the `strong_count` and `weak_count` values of the `Rc` instances change by creating a new inner scope and moving the creation of -`branch` into that scope. This will let us see what happens when `branch` is +`branch` into that scope. By doing so, we can see what happens when `branch` is created and then dropped when it goes out of scope. The modifications are shown -in Listing 15-33: +in Listing 15-29: Filename: src/main.rs -```rust,ignore +```rust +# use std::rc::{Rc, Weak}; +# use std::cell::RefCell; +# +# #[derive(Debug)] +# struct Node { +# value: i32, +# parent: RefCell>, +# children: RefCell>>, +# } +# fn main() { let leaf = Rc::new(Node { value: 3, @@ -486,6 +419,7 @@ fn main() { parent: RefCell::new(Weak::new()), children: RefCell::new(vec![Rc::clone(&leaf)]), }); + *leaf.parent.borrow_mut() = Rc::downgrade(&branch); println!( @@ -510,61 +444,53 @@ fn main() { } ``` -Listing 15-33: Creating `branch` in an inner scope and +Listing 15-29: Creating `branch` in an inner scope and examining strong and weak reference counts -Once `leaf` is created, its `Rc` has a strong count of 1 and a weak count of 0. -In the inner scope we create `branch` and associate it with `leaf`, at which -point the `Rc` in `branch` will have a strong count of 1 and a weak count of 1 -(for `leaf.parent` pointing to `branch` with a `Weak`). Here `leaf` will -have a strong count of 2, because `branch` now has a clone of the `Rc` of -`leaf` stored in `branch.children`, but will still have a weak count of 0. +After `leaf` is created, its `Rc` has a strong count of 1 and a weak +count of 0. In the inner scope, we create `branch` and associate it with +`leaf`, at which point when we print the counts, the `Rc` in `branch` +will have a strong count of 1 and a weak count of 1 (for `leaf.parent` pointing +to `branch` with a `Weak`). When we print the counts in `leaf`, we’ll see +it will have a strong count of 2, because `branch` now has a clone of the +`Rc` of `leaf` stored in `branch.children` but will still have a weak +count of 0. When the inner scope ends, `branch` goes out of scope and the strong count of -the `Rc` decreases to 0, so its `Node` gets dropped. The weak count of 1 from -`leaf.parent` has no bearing on whether `Node` is dropped or not, so we don’t -get any memory leaks! +the `Rc` decreases to 0, so its `Node` is dropped. The weak count of 1 +from `leaf.parent` has no bearing on whether or not `Node` is dropped, so we +don’t get any memory leaks! If we try to access the parent of `leaf` after the end of the scope, we’ll get -`None` again. At the end of the program, the `Rc` in `leaf` has a strong count -of 1 and a weak count of 0, because the variable `leaf` is now the only -reference to the `Rc` again. +`None` again. At the end of the program, the `Rc` in `leaf` has a strong +count of 1 and a weak count of 0, because the variable `leaf` is now the only +reference to the `Rc` again. - - - -All of the logic that manages the counts and value dropping is built in to -`Rc` and `Weak` and their implementations of the `Drop` trait. By specifying -that the relationship from a child to its parent should be a `Weak` -reference in the definition of `Node`, we’re able to have parent nodes point to -child nodes and vice versa without creating a reference cycle and memory leaks. - - - +All of the logic that manages the counts and value dropping is built into +`Rc` and `Weak` and their implementations of the `Drop` trait. By +specifying that the relationship from a child to its parent should be a +`Weak` reference in the definition of `Node`, we’re able to have parent +nodes point to child nodes and vice versa without creating a reference cycle +and memory leaks. ## Summary -This chapter covered how you can use smart pointers to make different -guarantees and tradeoffs than those Rust makes by default with regular -references. `Box` has a known size and points to data allocated on the heap. -`Rc` keeps track of the number of references to data on the heap so that -data can have multiple owners. `RefCell` with its interior mutability gives -us a type that can be used when we need an immutable type but need the ability -to change an inner value of that type, and enforces the borrowing rules at -runtime instead of at compile time. +This chapter covered how to use smart pointers to make different guarantees and +trade-offs than those Rust makes by default with regular references. The +`Box` type has a known size and points to data allocated on the heap. The +`Rc` type keeps track of the number of references to data on the heap, so +that data can have multiple owners. The `RefCell` type with its interior +mutability gives us a type that we can use when we need an immutable type but +need to change an inner value of that type; it also enforces the borrowing +rules at runtime instead of at compile time. -We also discussed the `Deref` and `Drop` traits that enable a lot of the +Also discussed were the `Deref` and `Drop` traits that enable a lot of the functionality of smart pointers. We explored reference cycles that can cause -memory leaks, and how to prevent them using `Weak`. +memory leaks and how to prevent them using `Weak`. If this chapter has piqued your interest and you want to implement your own -smart pointers, check out [“The Nomiconâ€] for even more useful information. +smart pointers, check out “The Rustonomicon†at +*https://doc.rust-lang.org/stable/nomicon/* for more useful information. -[“The Nomiconâ€]: https://doc.rust-lang.org/stable/nomicon/ - -Next, let’s talk about concurrency in Rust. We’ll even learn about a few new +Next, we’ll talk about concurrency in Rust. You’ll even learn about a few new smart pointers. diff --git a/src/doc/book/second-edition/src/ch16-00-concurrency.md b/src/doc/book/second-edition/src/ch16-00-concurrency.md index e06e6bff1e..8e7d728af9 100644 --- a/src/doc/book/second-edition/src/ch16-00-concurrency.md +++ b/src/doc/book/second-edition/src/ch16-00-concurrency.md @@ -3,60 +3,47 @@ Handling concurrent programming safely and efficiently is another of Rust’s major goals. *Concurrent programming*, where different parts of a program execute independently, and *parallel programming*, where different parts of a -program are executing at the same time, are becoming increasingly important as -more computers have multiple processors to take advantage of. Historically, +program execute at the same time, are becoming increasingly important as more +computers take advantage of their multiple processors. Historically, programming in these contexts has been difficult and error prone: Rust hopes to change that. Initially, the Rust team thought that ensuring memory safety and preventing concurrency problems were two separate challenges to be solved with different -methods. Over time, they discovered that the ownership and type systems are a -powerful set of tools to help in dealing with both memory safety *and* -concurrency problems! By leveraging ownership and type checking, many -concurrency errors are *compile time* errors in Rust, rather than runtime -errors. Rather than spending lots of time trying to reproduce the exact -circumstances under which a runtime concurrency bug occurs, incorrect code will -refuse to compile with an error explaining the problem. This lets you fix your -code while you’re working on it, rather than potentially after it’s been -shipped to production. We’ve nicknamed this aspect of Rust *fearless -concurrency*. Fearless concurrency allows you to write code that’s free of +methods. Over time, the team discovered that the ownership and type systems are +a powerful set of tools to help manage memory safety *and* concurrency +problems! By leveraging ownership and type checking, many concurrency errors +are *compile time* errors in Rust rather than runtime errors. Therefore, rather +than you spending lots of time trying to reproduce the exact circumstances +under which a runtime concurrency bug occurs, incorrect code will refuse to +compile and present an error explaining the problem. As a result, you can fix +your code while you’re working on it rather than potentially after it has been +shipped to production. We’ve nicknamed this aspect of Rust *fearless* +*concurrency*. Fearless concurrency allows you to write code that is free of 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 +> concurrent and/or parallel whenever we use concurrent. -> Note: we’ll be referring to many of the problems here as *concurrent* rather -> than being more precise by saying *concurrent and/or parallel*, for -> simplicity’s sake. If this were a book specifically about concurrency and/or -> parallelism, we’d be sure to be more specific. For this chapter, please -> mentally substitute *concurrent and/or parallel* whenever we say *concurrent*. +Many languages are dogmatic about the solutions they offer for handling +concurrent problems. For example, Erlang has elegant functionality for message +passing concurrency but has only obscure ways to share state between threads. +Supporting only a subset of possible solutions is a reasonable strategy for +higher-level languages, because a higher-level language promises benefits from +giving up some control to gain abstractions. However, lower-level languages are +expected to provide the solution with the best performance in any given +situation and have fewer abstractions over the hardware. Therefore, Rust offers +a variety of tools for modeling problems in whatever way is appropriate for +your situation and requirements. - - - -Many languages are strongly opinionated about the solutions they offer for -dealing with concurrent problems. For example, Erlang has elegant functionality -for message passing concurrency, but only obscure ways to share state between -threads. Only supporting a subset of possible solutions is a reasonable -strategy for higher-level languages to take, because a higher-level language -promises benefits from giving up some control in order to gain abstractions. -However, lower-level languages are expected to provide the solution with the -best performance in any given situation, and have fewer abstractions over the -hardware. Rust, therefore, gives us a variety of tools for modeling your -problems in whatever way is appropriate for your situation and requirements. - -Here’s what we’ll cover in this chapter: +Here are the topics we’ll cover in this chapter: * How to create threads to run multiple pieces of code at the same time -* *Message passing* concurrency, where channels are used to send messages - between threads. +* *Message passing* concurrency, where channels send messages between threads * *Shared state* concurrency, where multiple threads have access to some piece - of data. + of data * The `Sync` and `Send` traits, which extend Rust’s concurrency guarantees to - user-defined types as well as types provided by the standard library. + user-defined types as well as types provided by the standard library 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 56cf299a3e..38a7b2a86b 100644 --- a/src/doc/book/second-edition/src/ch16-01-threads.md +++ b/src/doc/book/second-edition/src/ch16-01-threads.md @@ -1,68 +1,53 @@ ## Using Threads to Run Code Simultaneously -In most operating systems today, an executed program’s code is run in a -*process*, and the operating system manages multiple process at once. Within +In most current operating systems, an executed program’s code is run in a +*process*, and the operating system manages multiple processes at once. Within your program, you can also have independent parts that run simultaneously. The feature that runs these independent parts is called *threads*. - - - -Splitting the computation in your program up into multiple threads can improve -performance, since the program will be doing multiple things at the same time, -but it also adds complexity. Because threads may run simultaneously, there’s no +Splitting the computation in your program into multiple threads can improve +performance because the program does multiple tasks at the same time, but it +also adds complexity. Because threads can run simultaneously, there’s no inherent guarantee about the order in which parts of your code on different -threads will run. This can lead to problems such as: +threads will run. This can lead to problems, such as: -- Race conditions, where threads are accessing data or resources in an +* Race conditions, where threads are accessing data or resources in an inconsistent order -- Deadlocks, where two threads are waiting for each other to finish using a - resource the other thread has, which prevents both threads from continuing -- Bugs that only happen in certain situations and are hard to reproduce and - fix reliably +* Deadlocks, where two threads are waiting for each other to finish using a + resource the other thread has, preventing both threads from continuing +* Bugs that only happen in certain situations and are hard to reproduce and fix + reliably - - - -Rust attempts to mitigate negative effects of using threads. Programming in a -multithreaded context still takes careful thought and requires a code structure -that’s different from programs that run in a single thread. +Rust attempts to mitigate the negative effects of using threads. Programming in +a multithreaded context still takes careful thought and requires a code +structure that is different from programs that run in a single thread. Programming languages implement threads in a few different ways. Many operating systems provide an API for creating new threads. This model where a language calls the operating system APIs to create threads is sometimes called *1:1*, -one OS thread per one language thread. +one operating system thread per one language thread. Many programming languages provide their own special implementation of threads. Programming language-provided threads are known as *green* threads, and languages that use these green threads will execute them in the context of a different number of operating system threads. For this reason, the green -threaded model is called the *M:N* model, `M` green threads per `N` OS threads, -where `M` and `N` are not necessarily the same number. +threaded model is called the *M:N* model: `M` green threads per `N` operating +system threads, where `M` and `N` are not necessarily the same number. -Each model has its own advantages and tradeoffs, and the tradeoff most -important to Rust is runtime support. *Runtime* is a confusing term and can -have different meanings in different contexts. +Each model has its own advantages and trade-offs, and the trade-off most +important to Rust is runtime support. Runtime is a confusing term and can have +different meanings in different contexts. - - - -In this context, by runtime we mean code that’s included by the language in +In this context, by *runtime* we mean code that is included by the language in every binary. This code can be large or small depending on the language, but every non-assembly language will have some amount of runtime code. For that -reason, colloquially when people say a language has “no runtime†they often +reason, colloquially when people say a language has “no runtime,†they often mean “small runtime.†Smaller runtimes have fewer features but have the advantage of resulting in smaller binaries, which make it easier to combine the -language with other languages in more contexts. While many languages are okay -with increasing the runtime size in exchange for more features, Rust needs to -have nearly no runtime, and cannot compromise on being able to call into C in -order to maintain performance. +language with other languages in more contexts. Although many languages are +okay with increasing the runtime size in exchange for more features, Rust needs +to have nearly no runtime and cannot compromise on being able to call into C to +maintain performance. The green threading M:N model requires a larger language runtime to manage threads. As such, the Rust standard library only provides an implementation of @@ -76,7 +61,7 @@ thread-related API provided by the standard library. ### Creating a New Thread with `spawn` -To create a new thread, we call the `thread::spawn` function, and pass it a +To create a new thread, we call the `thread::spawn` function and pass it a closure (we talked about closures in Chapter 13) containing the code we want to run in the new thread. The example in Listing 16-1 prints some text from a main thread and other text from a new thread: @@ -106,9 +91,9 @@ fn main() { while the main thread prints something else Note that with this function, the new thread will be stopped when the main -thread ends, whether it has finished running or not. The output from this -program might be a little different every time, but it will look similar to -this: +thread ends, whether or not it has finished running. The output from this +program might be a little different every time, but it will look similar to the +following: ```text hi number 1 from the main thread! @@ -122,44 +107,32 @@ hi number 4 from the spawned thread! hi number 5 from the spawned thread! ``` - - - -The `thread::sleep` function will force a thread to stop its execution for a -short duration, allowing a different thread to run, so that they will probably -take turns, but that’s not guaranteed: it depends on how your operating system -schedules the threads. In this run, the main thread printed first, even though +The calls to `thread::sleep` force a thread to stop its execution for a short +duration, which allows a different thread to run. The threads will probably +take turns, but that isn’t guaranteed: it depends on how your operating system +schedules the threads. In this run, the main thread printed first, even though the print statement from the spawned thread appears first in the code. And even -though we told the spawned thread to print until `i` is 9, it only got to 5 +though we told the spawned thread to print until `i` is 9, it only got to 5 before the main thread shut down. -If you run this code and only see one thread, or don’t see any overlap, try -increasing the numbers in the ranges to create more opportunities for a thread -to take a break and give the other thread a turn. +If you run this code and only see output from the main thread, or don’t see any +overlap, try increasing the numbers in the ranges to create more opportunities +for the operating system to switch between the threads. -#### Waiting for All Threads to Finish Using `join` Handles +### 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, because the main thread ends before the spawned thread is done, -there’s actually no guarantee that the spawned thread will get to run at all, -because there’s no guarantee on the order in which threads run! +the time due to the main thread ending, but there is no 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! - - - -We can fix this by saving the return value of `thread::spawn` in a variable. +We can fix the problem of the spawned thread not getting to run, or not getting +to run completely, by saving the return value of `thread::spawn` in a variable. The return type of `thread::spawn` is `JoinHandle`. A `JoinHandle` is an owned value that, when we call the `join` method on it, will wait for its thread to finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created -in Listing 16-1 and call `join` in order to make sure the spawned thread -finishes before the `main` exits: - - - +in Listing 16-1 and call `join` to make sure the spawned thread finishes before +`main` exits: Filename: src/main.rs @@ -180,7 +153,7 @@ fn main() { thread::sleep(Duration::from_millis(1)); } - handle.join(); + handle.join().unwrap(); } ``` @@ -190,12 +163,8 @@ to guarantee the thread is run to completion Calling `join` on the handle blocks the thread currently running until the thread represented by the handle terminates. *Blocking* a thread means that thread is prevented from performing work or exiting. Because we’ve put the call -to `join` after the main thread’s `for` loop, running this example should -produce output that looks something like this: - - +to `join` after the main thread’s `for` loop, running Listing 16-2 should +produce output similar to this: ```text hi number 1 from the main thread! @@ -213,10 +182,11 @@ hi number 8 from the spawned thread! hi number 9 from the spawned thread! ``` -The two threads are still alternating, but the main thread waits because of the +The two threads continue alternating, but the main thread waits because of the call to `handle.join()` and does not end until the spawned thread is finished. -If we instead move `handle.join()` before the `for` loop in main, like this: +But let’s see what happens when we instead move `handle.join()` before the +`for` loop in `main`, like this: Filename: src/main.rs @@ -232,7 +202,7 @@ fn main() { } }); - handle.join(); + handle.join().unwrap(); for i in 1..5 { println!("hi number {} from the main thread!", i); @@ -242,7 +212,7 @@ fn main() { ``` The main thread will wait for the spawned thread to finish and then run its -`for` loop, so the output won’t be interleaved anymore: +`for` loop, so the output won’t be interleaved anymore, as shown here: ```text hi number 1 from the spawned thread! @@ -260,29 +230,29 @@ hi number 3 from the main thread! hi number 4 from the main thread! ``` -Thinking about a small thing such as where to call `join` can affect whether -your threads are actually running at the same time or not. +Thinking about such a small detail as where to call `join` can affect whether +or not your threads run at the same time. ### Using `move` Closures with Threads -The `move` closure, which we didn’t cover in Chapter 13, is often used -alongside `thread::spawn`, as it allows us to use data from one thread in +The `move` closure, which we mentioned briefly in Chapter 13, is often used +alongside `thread::spawn` because it allows us to use data from one thread in another thread. -In Chapter 13, we said that “Creating closures that capture values from their -environment is mostly used in the context of starting new threads.†+In Chapter 13, we said that “If we want to force the closure to take ownership +of the values it uses in the environment, we can use the `move` keyword before +the parameter list. This technique is mostly useful when passing a closure to a +new thread to move the data so it’s owned by the new thread.†- - -Now we’re creating new threads, so let’s talk about capturing values in -closures! +Now that we’re creating new threads, we’ll talk about capturing values in +closures. Notice in Listing 16-1 that the closure we pass to `thread::spawn` takes no arguments: we’re not using any data from the main thread in the spawned -thread’s code. In order to do so, the spawned thread’s closure must capture the -values it needs. Listing 16-3 shows an attempt to create a vector in the main -thread and use it in the spawned thread. However, this won’t yet work, as -you’ll see in a moment: +thread’s code. To do so, the spawned thread’s closure must capture the values +it needs. Listing 16-3 shows an attempt to create a vector in the main thread +and use it in the spawned thread. However, this won’t yet work, as you’ll see +in a moment: Filename: src/main.rs @@ -296,23 +266,22 @@ fn main() { println!("Here's a vector: {:?}", v); }); - handle.join(); + handle.join().unwrap(); } ``` Listing 16-3: Attempting to use a vector created by the main thread in another thread -The closure uses `v`, so will capture `v` and make it part of the closure’s +The closure uses `v`, so it will capture `v` and make it part of the closure’s environment. Because `thread::spawn` runs this closure in a new thread, we -should be able to access `v` inside that new thread. - -When we compile this example, however, we’ll get the following error: +should be able to access `v` inside that new thread. But when we compile this +example, we get the following error: ```text error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function - --> + --> src/main.rs:6:32 | 6 | let handle = thread::spawn(|| { | ^^ may outlive borrowed value `v` @@ -320,17 +289,19 @@ which is owned by the current function | - `v` is borrowed here | help: to force the closure to take ownership of `v` (and any other referenced -variables), use the `move` keyword, as shown: - | let handle = thread::spawn(move || { +variables), use the `move` keyword + | +6 | let handle = thread::spawn(move || { + | ^^^^^^^ ``` -Rust *infers* how to capture `v`, and since `println!` only needs a reference -to `v`, the closure tries to borrow `v`. There’s a problem, though: Rust can’t -tell how long the spawned thread will run, so doesn’t know if the reference to -`v` will always be valid. +Rust *infers* how to capture `v`, and because `println!` only needs a reference +to `v`, the closure tries to borrow `v`. However, there’s a problem: Rust can’t +tell how long the spawned thread will run, so it doesn’t know if the reference +to `v` will always be valid. -Let’s look at a scenario that’s more likely to have a reference to `v` that -won’t be valid, shown Listing 16-4: +Listing 16-4 provides a scenario that’s more likely to have a reference to `v` +that won’t be valid: Filename: src/main.rs @@ -346,33 +317,35 @@ fn main() { drop(v); // oh no! - handle.join(); + handle.join().unwrap(); } ``` Listing 16-4: A thread with a closure that attempts to capture a reference to `v` from a main thread that drops `v` -If we run this code, there’s a possibility the spawned thread will be -immediately put in the background without getting a chance to run at all. The -spawned thread has a reference to `v` inside, but the main thread immediately -drops `v`, using the `drop` function we discussed in Chapter 15. Then, when the +If we were allowed to run this code, there’s a possibility the spawned thread +will be immediately put in the background without running at all. The spawned +thread has a reference to `v` inside, but the main thread immediately drops +`v`, using the `drop` function we discussed in Chapter 15. Then, when the spawned thread starts to execute, `v` is no longer valid, so a reference to it is also invalid. Oh no! -To fix the problem in Listing 16-3, we can listen to the advice of the error -message: +To fix the compiler error in Listing 16-3, we can use the error message’s +advice: ```text help: to force the closure to take ownership of `v` (and any other referenced -variables), use the `move` keyword, as shown: - | let handle = thread::spawn(move || { +variables), use the `move` keyword + | +6 | let handle = thread::spawn(move || { + | ^^^^^^^ ``` By adding the `move` keyword before the closure, we force the closure to take -ownership of the values it’s using, rather than allowing Rust to infer that it -should borrow. The modification to Listing 16-3 shown in Listing 16-5 will -compile and run as we intend: +ownership of the values it’s using rather than allowing Rust to infer that it +should borrow the values. The modification to Listing 16-3 shown in Listing +16-5 will compile and run as we intend: Filename: src/main.rs @@ -386,26 +359,23 @@ fn main() { println!("Here's a vector: {:?}", v); }); - handle.join(); + handle.join().unwrap(); } ``` Listing 16-5: Using the `move` keyword to force a closure to take ownership of the values it uses - - - What would happen to the code in Listing 16-4 where the main thread called -`drop` if we use a `move` closure? Would `move` fix that case? Nope, we get a -different error, because what Listing 16-4 is trying to do isn’t allowed for a -different reason! If we add `move` to the closure, we’d move `v` into the -closure’s environment, and we could no longer call `drop` on it in the main -thread. We would get this compiler error instead: +`drop` if we use a `move` closure? Would `move` fix that case? Unfortunately, +no; we would get a different error because what Listing 16-4 is trying to do +isn’t allowed for a different reason. If we add `move` to the closure, we would +move `v` into the closure’s environment, and we could no longer call `drop` on +it in the main thread. We would get this compiler error instead: ```text error[E0382]: use of moved value: `v` - --> + --> src/main.rs:10:10 | 6 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -421,16 +391,11 @@ Rust’s ownership rules have saved us again! We got an error from the code in Listing 16-3 because Rust was being conservative and only borrowing `v` for the thread, which meant the main thread could theoretically invalidate the spawned thread’s reference. By telling Rust to move ownership of `v` to the spawned -thread, we’re guaranteeing to Rust that the main thread won’t use `v` anymore. -If we change Listing 16-4 in the same way, we’re then violating the ownership +thread, we’re guaranteeing Rust that the main thread won’t use `v` anymore. If +we change Listing 16-4 in the same way, we’re then violating the ownership rules when we try to use `v` in the main thread. The `move` keyword overrides Rust’s conservative default of borrowing; it doesn’t let us violate the ownership rules. - - - -Now that we have a basic understanding of threads and the thread API, let’s -talk about what we can actually *do* with threads. +With a basic understanding of threads and the thread API, let’s look at what we +can *do* with threads. 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 f13bf26a70..3c4e1c2a23 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 @@ -2,17 +2,13 @@ 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 slogan form from the Go language -documentation: +containing data. Here’s the idea in a slogan from the Go language documentation: > Do not communicate by sharing memory; instead, share memory by > communicating. > > --[Effective Go](http://golang.org/doc/effective_go.html) - - - One major tool Rust has for accomplishing message sending concurrency is the *channel*, a programming concept that Rust’s standard library provides an implementation of. You can imagine a channel in programming like a channel of @@ -20,20 +16,24 @@ water, such as a stream or a river. If you put something like a rubber duck or a boat into a stream, it will travel downstream to the end of the river. A channel in programming has two halves: a transmitter and a receiver. The -transmitter half is like the upstream location where we put rubber ducks into -the river, and the receiver half is the downstream place where the rubber duck -ends up. One part of our code calls methods on the transmitter with the data we -want to send, and another part checks the receiving end for arriving messages. +transmitter half is the upstream location where we put rubber ducks into the +river, and the receiver half is where the rubber duck ends up downstream. One +part of our code calls methods on the transmitter with the data we want to +send, and another part checks the receiving end for arriving messages. A +channel is said to be *closed* if either the transmitter or receiver half is +dropped. -Here we’ll work up to a program that has one thread to generate values and send -them down a channel, and another thread that will receive the values and print -them out. We’re going to be sending simple values between threads using a -channel for the purposes of illustration. Once you’re familiar with the -technique, you could use channels to implement a chat system, or a system where -many threads perform parts of a calculation and send the parts to one thread -that aggregates the results. +Here, we’ll work up to a program that has one thread to generate values and +send them down a channel, and another thread that will receive the values and +print them out. We’ll be sending simple values between threads using a channel +to illustrate the feature. Once you’re familiar with the technique, you could +use channels to implement a chat system or a system where many threads perform +parts of a calculation and send the parts to one thread that aggregates the +results. -First, we’ll create a channel but not do anything with it in Listing 16-6: +First, in Listing 16-6, we’ll create a channel but not do anything with it. +Note that this won’t compile yet because Rust can’t tell what type of values we +want to send over the channel: Filename: src/main.rs @@ -51,39 +51,29 @@ halves to `tx` and `rx` We create a new channel using the `mpsc::channel` function; `mpsc` stands for *multiple producer, single consumer*. In short, the way Rust’s standard library -has implemented channels is such that a channel can have multiple *sending* -ends that produce values, but only one *receiving* end that consumes those -values. Imagine multiple rivers and streams flowing together into one big -river: everything sent down any of the streams will end up in one river at the -end. We’re going to start with a single producer for now, but we’ll add -multiple producers once we get this example working. +implements channels means a channel can have multiple *sending* ends that +produce values but only one *receiving* end that consumes those values. Imagine +multiple rivers and streams flowing together into one big river: everything +sent down any of the streams will end up in one river at the end. We’ll start +with a single producer for now, but we’ll add multiple producers when we get +this example working. The `mpsc::channel` function returns a tuple, the first element of which is the -sending end and the second element the receiving end. The abbreviations `tx` +sending end and the second element is the receiving end. The abbreviations `tx` and `rx` are traditionally used in many fields for *transmitter* and *receiver* -respectively, so we give our variables those names to indicate each end. We’re -using a `let` statement with a pattern that destructures the tuples; we’ll be -discussing the use of patterns in `let` statements and destructuring in -Chapter 18. Using a `let` statement in this way is a convenient way to extract -the pieces of the tuple returned by `mpsc::channel`. - - - +respectively, so we name our variables as such to indicate each end. We’re +using a `let` statement with a pattern that destructures the tuples; we’ll +discuss the use of patterns in `let` statements and destructuring in +Chapter 18. Using a `let` statement this way is a convenient approach to +extract the pieces of the tuple returned by `mpsc::channel`. Let’s move the transmitting end into a spawned thread and have it send one -string so that the spawned thread is communicating with the main thread, shown -in Listing 16-7. This is like putting a rubber duck in the river upstream or +string so the spawned thread is communicating with the main thread, as shown in +Listing 16-7. This is like putting a rubber duck in the river upstream or sending a chat message from one thread to another: - - - Filename: src/main.rs ```rust @@ -103,21 +93,21 @@ fn main() { Listing 16-7: Moving `tx` to a spawned thread and sending “hi†-We’re again using `thread::spawn` to create a new thread, and then use `move` +Again, we’re using `thread::spawn` to create a new thread and then using `move` to move `tx` into the closure so the spawned thread owns `tx`. The spawned -thread needs to own the transmitting end of the channel in order to be able to -send messages through the channel. +thread needs to own the transmitting end of the channel to be able to send +messages through the channel. The transmitting end has a `send` method that takes the value we want to send. -The `send` method returns a `Result` type, so that if the receiving end -has already been dropped and there’s nowhere to send a value, the send -operation will error. In this example, we’re simply calling `unwrap` to panic -in case of error, but for a real application, we’d handle it properly--return -to Chapter 9 to review strategies for proper error handling. +The `send` method returns a `Result` type, so if the receiving end has +already been dropped and there’s nowhere to send a value, the send operation +will return an error. In this example, we’re calling `unwrap` to panic in case +of an error. But in a real application, we would handle it properly: return to +Chapter 9 to review strategies for proper error handling. In Listing 16-8, we’ll get the value from the receiving end of the channel in the main thread. This is like retrieving the rubber duck from the water at the -end of the river, or like getting a chat message: +end of the river or like getting a chat message: Filename: src/main.rs @@ -139,7 +129,7 @@ fn main() { ``` Listing 16-8: Receiving the value “hi†in the main thread -and printing it out +and printing it The receiving end of a channel has two useful methods: `recv` and `try_recv`. We’re using `recv`, short for *receive*, which will block the main thread’s @@ -148,29 +138,20 @@ sent, `recv` will return it in a `Result`. When the sending end of the channel closes, `recv` will return an error to signal that no more values will be coming. - - - The `try_recv` method doesn’t block, but will instead return a `Result` -immediately: an `Ok` value holding a message if one is available, and an `Err` +immediately: an `Ok` value holding a message if one is available and an `Err` value if there aren’t any messages this time. Using `try_recv` is useful if this thread has other work to do while waiting for messages: we could write a loop that calls `try_recv` every so often, handles a message if one is available, and otherwise does other work for a little while until checking again. -We’ve chosen to use `recv` in this example for simplicity; we don’t have any -other work for the main thread to do other than wait for messages, so blocking -the main thread is appropriate. +We’ve used `recv` in this example for simplicity; we don’t have any other work +for the main thread to do other than wait for messages, so blocking the main +thread is appropriate. - - - -If we run the code in Listing 16-8, we’ll see the value printed out from the -main thread: +When we run the code in Listing 16-8, we’ll see the value printed from the main +thread: ```text Got: hi @@ -180,21 +161,9 @@ Perfect! ### Channels and Ownership Transference - - - -The ownership rules play a vital role in message sending as far as helping us +The ownership rules play a vital role in message sending because they help us write safe, concurrent code. Preventing errors in concurrent programming is the -advantage we get by making the tradeoff of having to think about ownership +advantage we get by making the trade-off of having to think about ownership throughout our 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 @@ -220,16 +189,15 @@ fn main() { } ``` -Listing 16-9: Attempting to use `val` after we have sent -it down the channel +Listing 16-9: Attempting to use `val` after we’ve sent it +down the channel -Here, we try to print out `val` after we’ve sent it down the channel via -`tx.send`. Allowing this would be a bad idea: once the value has been sent to -another thread, that thread could modify or drop it before we try to use the -value again, which would potentially cause errors or unexpected results due to -inconsistent or nonexistent data. - -However, Rust gives us an error if we try to compile this code: +Here, we try to print `val` after we’ve sent it down the channel via `tx.send`. +Allowing this would be a bad idea: once the value has been sent to another +thread, that thread could modify or drop it before we try to use the value +again. Potentially, the other thread's modifications could cause errors or +unexpected results due to inconsistent or nonexistent data. However, Rust gives +us an error if we try to compile the code in Listing 16-9: ```text error[E0382]: use of moved value: `val` @@ -241,21 +209,21 @@ error[E0382]: use of moved value: `val` | ^^^ value used here after move | = note: move occurs because `val` has type `std::string::String`, which does - not implement the `Copy` trait +not implement the `Copy` trait ``` -Our concurrency mistake has caused a compile-time error! The `send` function -takes ownership of its parameter, and when the value is moved the receiver +Our concurrency mistake has caused a compile time error. The `send` function +takes ownership of its parameter, and when the value is moved, the receiver takes ownership of it. This stops us from accidentally using the value again after sending it; the ownership system checks that everything is okay. ### Sending Multiple Values and Seeing the Receiver Waiting -The code in Listing 16-8 compiled and ran, but doesn’t show us very clearly -that two separate threads are talking to each other over the channel. In -Listing 16-10 we’ve made some modifications that will prove this code is +The code in Listing 16-8 compiled and ran, but it didn’t clearly show us that +two separate threads were talking to each other over the channel. In Listing +16-10 we’ve made some modifications that will prove the code in Listing 16-8 is running concurrently: the spawned thread will now send multiple messages and -pause for a second between each message. +pause for a second between each message: Filename: src/main.rs @@ -296,10 +264,10 @@ between each by calling the `thread::sleep` function with a `Duration` value of one second. In the main thread, we’re not calling the `recv` function explicitly anymore: -instead we’re treating `rx` as an iterator. For each value received, we’re -printing it out. When the channel is closed, iteration will end. +instead, we’re treating `rx` as an iterator. For each value received, we’re +printing it. When the channel is closed, iteration will end. -When running the code in Listing 16-10, you should see the following output, +When running the code in Listing 16-10, you should see the following output with a one second pause in between each line: ```text @@ -313,22 +281,12 @@ Because we don’t have any code that pauses or delays in the `for` loop in the main thread, we can tell that the main thread is waiting to receive values from the spawned thread. - - - ### Creating Multiple Producers by Cloning the Transmitter -Near the start of this section, we mentioned that `mpsc` stood for *multiple -producer, single consumer*. Let’s put that ability to use and expand the code -from Listing 16-10 to create multiple threads that all send values to the same -receiver. We can do that by cloning the transmitting half of the channel, as -shown in Listing 16-11: +Earlier we mentioned that `mpsc` was an acronym for *multiple* *producer, +single consumer*. Let’s put `mpsc` to use and expand the code in Listing 16-10 +to create multiple threads that all send values to the same receiver. We can do +so by cloning the transmitting half of the channel, as shown in Listing 16-11: Filename: src/main.rs @@ -339,6 +297,7 @@ shown in Listing 16-11: # # fn main() { // --snip-- + let (tx, rx) = mpsc::channel(); let tx1 = mpsc::Sender::clone(&tx); @@ -369,11 +328,12 @@ thread::spawn(move || { thread::sleep(Duration::from_secs(1)); } }); + +for received in rx { + println!("Got: {}", received); +} + // --snip-- -# -# for received in rx { -# println!("Got: {}", received); -# } # } ``` @@ -386,7 +346,7 @@ to the first spawned thread. We pass the original sending end of the channel to a second spawned thread. This gives us two threads, each sending different messages to the receiving end of the channel. -If you run this, you’ll *probably* see output like this: +When you run the code, you’ll *probably* see output like this: ```text Got: hi @@ -399,10 +359,10 @@ Got: thread Got: you ``` -You might see the values in a different order, it depends on your system! This -is what makes concurrency interesting as well as difficult. If you play around -with `thread::sleep`, giving it different values in the different threads, each -run will be more non-deterministic and create different output each time. +You might see the values in another order; it depends on your system. This is +what makes concurrency interesting as well as difficult. If you experiment with +`thread::sleep`, giving it various values in the different threads, each run +will be more non-deterministic and create different output each time. -Now that we’ve seen how channels work, let’s look at a different method of +Now that we’ve looked at how channels work, let’s look at a different method of concurrency. diff --git a/src/doc/book/second-edition/src/ch16-03-shared-state.md b/src/doc/book/second-edition/src/ch16-03-shared-state.md index 8c2f28da18..90e6d12ef3 100644 --- a/src/doc/book/second-edition/src/ch16-03-shared-state.md +++ b/src/doc/book/second-edition/src/ch16-03-shared-state.md @@ -1,70 +1,55 @@ ## Shared State Concurrency -Message passing is a fine way of dealing with concurrency, but it’s not the -only one. Consider this slogan again: +Message passing is a fine way of handling concurrency, but it’s not the only +one. Consider this part of the slogan from the Go language documentation again: +“communicate by sharing memory.†-> Do not communicate by sharing memory; instead, share memory by -> communicating. +What would communicating by sharing memory look like? In addition, why would +message passing enthusiasts not use it and do the opposite instead? -What would “communicate by sharing memory†look like? And moreover, why would -message passing enthusiasts choose not to use it and do the opposite instead? - - - - -In a way, channels in any programming language are sort of like single -ownership, because once you transfer a value down a channel, you shouldn’t use -that value any longer. Shared memory concurrency is sort of like multiple -ownership: multiple threads can access the same memory location at the same -time. As we saw in Chapter 15 where multiple ownership was made possible by -smart pointers, multiple ownership can add additional complexity because these -different owners need managing. - -Rust’s type system and ownership rules assist a lot in getting this management -correct, though. For an example, let’s look at one of the more common -concurrency primitives for shared memory: mutexes. +In a way, channels in any programming language are similar to single ownership, +because once you transfer a value down a channel, you should no longer use that +value. Shared memory concurrency is like multiple ownership: multiple threads +can access the same memory location at the same time. As you saw in Chapter 15 +where smart pointers made multiple ownership possible, multiple ownership can +add additional complexity because these different owners need managing. Rust’s +type system and ownership rules greatly assist in getting this management +correct. For an example, let’s look at mutexes, one of the more common +concurrency primitives for shared memory. ### Mutexes Allow Access to Data from One Thread at a Time -A *mutex* is a concurrency primitive for sharing memory. It’s short for “mutual -exclusionâ€, as in, it only allows one thread to access some data at any given -time. In order to access the data in a mutex, a thread must first signal that -it wants access by asking to acquire the mutex’s *lock*. The lock is a data -structure that is part of the mutex that keeps track of who currently has -exclusive access to the data. We therefore describe the mutex as *guarding* the -data it holds via the locking system. +A *mutex* is an abbreviation for “mutual exclusion,†as in, it only allows one +thread to access some data at any given time. To access the data in a mutex, a +thread must first signal that it wants access by asking to acquire the mutex’s +*lock*. The lock is a data structure that is part of the mutex that keeps track +of who currently has exclusive access to the data. Therefore, we describe the +mutex as *guarding* the data it holds via the locking system. -Mutexes have a reputation for being hard to use because there are some -rules you have to remember: - - - +Mutexes have a reputation for being difficult to use because you have to +remember two rules: 1. You must attempt to acquire the lock before using the data. -2. Once you’re done with the data that’s guarded by the mutex, you must unlock - the data so other threads can acquire the lock. +2. When you’re done with the data that the mutex guards, you must unlock the + data so other threads can acquire the lock. For a real-world metaphor of a mutex, imagine a panel discussion at a -conference with only one microphone. Before a panelist may speak, they have to -ask or signal that they would like to use the microphone. Once they get the -microphone, they may talk for as long as they would like, then hand the +conference with only one microphone. Before a panelist can speak, they have to +ask or signal that they want to use the microphone. When they get the +microphone, they can talk for as long as they want to and then hand the microphone to the next panelist who requests to speak. If a panelist forgets to hand the microphone off when they’re finished with it, no one else is able to -speak. If management of the shared microphone goes wrong, the panel would not +speak. If management of the shared microphone goes wrong, the panel wouldn’t work as planned! -Management of mutexes can be incredibly tricky to get right, and that’s why so +Management of mutexes can be incredibly tricky to get right, which is why so many people are enthusiastic about channels. However, thanks to Rust’s type system and ownership rules, we can’t get locking and unlocking wrong. #### The API of `Mutex` -Let’s start simply with an example of using a mutex in a single-threaded -context, shown in Listing 16-12: +As an example of how to use a mutex, let’s start by using a mutex in a +single-threaded context, as shown in Listing 16-12: Filename: src/main.rs @@ -84,48 +69,41 @@ fn main() { ``` Listing 16-12: Exploring the API of `Mutex` in a -single threaded context for simplicity +single-threaded context for simplicity As with many types, we create a `Mutex` using the associated function `new`. To access the data inside the mutex, we use the `lock` method to acquire the -lock. This call will block the current thread so that it can’t do any work -until it’s our turn to have the lock. - - - +lock. This call will block the current thread so it can’t do any work until +it’s our turn to have the lock. The call to `lock` would fail if another thread holding the lock panicked. In that case, no one would ever be able to get the lock, so we’ve chosen to `unwrap` and have this thread panic if we’re in that situation. - - - -Once we’ve acquired the lock, we can treat the return value, named `num` in +After we’ve acquired the lock, we can treat the return value, named `num` in this case, as a mutable reference to the data inside. The type system ensures -that we acquire a lock before using this value: `Mutex` is not an `i32`, -so we *must* acquire the lock in order to be able to use the `i32` value. We -can’t forget; the type system won’t let us do it otherwise. +that we acquire a lock before using the value in `m`: `Mutex` is not an +`i32`, so we *must* acquire the lock to be able to use the `i32` value. We +can’t forget; the type system won’t let us access the inner `i32` otherwise. -As you may suspect, `Mutex` is a smart pointer. More accurately, the call to -`lock` *returns* a smart pointer called `MutexGuard`. This smart pointer -implements `Deref` to point at our inner data, and also has a `Drop` -implementation that releases the lock automatically when `MutexGuard` goes out -of scope, which happens at the end of the inner scope in Listing 16-12. This -way, we don’t risk forgetting to release the lock and blocking it from use by -other threads, because it happens automatically. +As you might suspect, `Mutex` is a smart pointer. More accurately, the call +to `lock` *returns* a smart pointer called `MutexGuard`. This smart pointer +implements `Deref` to point at our inner data; the smart pointer also has a +`Drop` implementation that releases the lock automatically when a `MutexGuard` +goes out of scope, which happens at the end of the inner scope in Listing +16-12. As a result, we don’t risk forgetting to release the lock and blocking +the mutex from being used by other threads because the lock release happens +automatically. -After dropping the lock, we can print out the mutex value and see that we were -able to change the inner `i32` to 6. +After dropping the lock, we can print the mutex value and see that we were able +to change the inner `i32` to 6. #### Sharing a `Mutex` Between Multiple Threads -Let’s now try to share a value between multiple threads using `Mutex`. We’ll -spin up ten threads, and have them each increment a counter value by 1 so that +Now, let’s try to share a value between multiple threads using `Mutex`. +We’ll spin up 10 threads and have them each increment a counter value by 1, so the counter goes from 0 to 10. Note that the next few examples will have -compiler errors, and we’re going to use those errors to learn more about using +compiler errors, and we’ll use those errors to learn more about using `Mutex` and how Rust helps us use it correctly. Listing 16-13 has our starting example: @@ -159,29 +137,24 @@ fn main() { Listing 16-13: Ten threads each increment a counter guarded by a `Mutex` -We’re creating a `counter` variable to hold an `i32` inside a `Mutex`, like -we did in Listing 16-12. Next, we’re creating 10 threads by mapping over a -range of numbers. We use `thread::spawn` and give all the threads the same -closure, one that moves the counter into the thread, acquires a lock on the -`Mutex` by calling the `lock` method, and then adds 1 to the value in the -mutex. When a thread finishes running its closure, `num` will go out of scope -and release the lock so another thread can acquire it. +We’re creating a `counter` variable to hold an `i32` inside a `Mutex`, as we +did in Listing 16-12. Next, we’re creating 10 threads by mapping over a range +of numbers. We use `thread::spawn` and give all the threads the same closure, +one that moves the counter into the thread, acquires a lock on the `Mutex` +by calling the `lock` method, and then adds 1 to the value in the mutex. When a +thread finishes running its closure, `num` will go out of scope and release the +lock so another thread can acquire it. -In the main thread, we collect all the join handles like we did in Listing -16-2, and then call `join` on each to make sure all the threads finish. At that -point, the main thread will acquire the lock and print out the result of this +In the main thread, we collect all the join handles, as we did in Listing 16-2, +and then call `join` on each to make sure all the threads finish. At that +point, the main thread will acquire the lock and print the result of this program. We hinted that this example won’t compile, now let’s find out why! - - - ```text error[E0382]: capture of moved value: `counter` - --> + --> src/main.rs:10:27 | 9 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -192,7 +165,7 @@ error[E0382]: capture of moved value: `counter` which does not implement the `Copy` trait error[E0382]: use of moved value: `counter` - --> + --> src/main.rs:21:29 | 9 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -206,14 +179,13 @@ error[E0382]: use of moved value: `counter` error: aborting due to 2 previous errors ``` -The error message is saying that the `counter` value is moved into the closure, -then is captured when we call `lock`. That sounds like what we wanted, but it’s -not allowed! +The error message states that the `counter` value is moved into the closure and +then is captured when we call `lock`. That description sounds like what we +wanted, but it’s not allowed! -Let’s reason this out by simplifying the program. Instead of making 10 threads +Let’s figure this out by simplifying the program. Instead of making 10 threads in a `for` loop, let’s just make two threads without a loop and see what -happens then. Replace the first `for` loop in Listing 16-13 with this code -instead: +happens. Replace the first `for` loop in Listing 16-13 with this code instead: ```rust,ignore let handle = thread::spawn(move || { @@ -232,11 +204,12 @@ handles.push(handle2); ``` We make two threads and change the variable names used with the second thread -to `handle2` and `num2`. When we run this time, compiling gives us: +to `handle2` and `num2`. When we run the code this time, compiling gives us the +following: ```text error[E0382]: capture of moved value: `counter` - --> + --> src/main.rs:16:24 | 8 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -248,7 +221,7 @@ error[E0382]: capture of moved value: `counter` which does not implement the `Copy` trait error[E0382]: use of moved value: `counter` - --> + --> src/main.rs:26:29 | 8 | let handle = thread::spawn(move || { | ------- value moved (into closure) here @@ -262,23 +235,23 @@ error[E0382]: use of moved value: `counter` error: aborting due to 2 previous errors ``` -Aha! The first error message tells us that `counter` is moved into the closure +Aha! The first error message indicates that `counter` is moved into the closure for the thread associated with `handle`. That move is preventing us from capturing `counter` when we try to call `lock` on it and store the result in `num2` in the second thread! So Rust is telling us that we can’t move ownership -of `counter` into multiple threads. This was hard to see before because our +of `counter` into multiple threads. This was hard to see earlier because our threads were in a loop, and Rust can’t point to different threads in different -iterations of the loop. Let’s try to fix this with a multiple-ownership method -we saw in Chapter 15. +iterations of the loop. Let’s fix the compiler error with a multiple-ownership +method we discussed in Chapter 15. #### Multiple Ownership with Multiple Threads -In Chapter 15, we were able to give a value multiple owners by using the smart -pointer `Rc` to create a reference-counted value. Let’s try to do the same -here and see what happens. We’ll wrap the `Mutex` in `Rc` in Listing -16-14, and clone the `Rc` before moving ownership to the thread. Now we’ve -seen the errors, we’ll also switch back to using the `for` loop, and we’ll keep -the `move` keyword with the closure: +In Chapter 15, we gave a value multiple owners by using the smart pointer +`Rc` to create a reference-counted value. Let’s do the same here and see +what happens. We’ll wrap the `Mutex` in `Rc` in Listing 16-14 and clone +the `Rc` before moving ownership to the thread. Now that we’ve seen the +errors, we’ll also switch back to using the `for` loop, and we’ll keep the +`move` keyword with the closure: Filename: src/main.rs @@ -292,7 +265,7 @@ fn main() { let mut handles = vec![]; for _ in 0..10 { - let counter = Rc::clone(&counter); + let counter = Rc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); @@ -313,66 +286,65 @@ fn main() { multiple threads to own the `Mutex` Once again, we compile and get... different errors! The compiler is teaching us -a lot! +a lot. ```text error[E0277]: the trait bound `std::rc::Rc>: -std::marker::Send` is not satisfied - --> +std::marker::Send` is not satisfied in `[closure@src/main.rs:11:36: +15:10 +counter:std::rc::Rc>]` + --> src/main.rs:11:22 | 11 | let handle = thread::spawn(move || { - | ^^^^^^^^^^^^^ the trait `std::marker::Send` is not - implemented for `std::rc::Rc>` + | ^^^^^^^^^^^^^ `std::rc::Rc>` +cannot be sent between threads safely | - = note: `std::rc::Rc>` cannot be sent between threads - safely + = help: within `[closure@src/main.rs:11:36: 15:10 +counter:std::rc::Rc>]`, the trait `std::marker::Send` is +not implemented for `std::rc::Rc>` = note: required because it appears within the type - `[closure@src/main.rs:11:36: 15:10 - counter:std::rc::Rc>]` +`[closure@src/main.rs:11:36: 15:10 +counter:std::rc::Rc>]` = note: required by `std::thread::spawn` ``` -Wow, that’s quite wordy! Here are some important parts to pick out: the first -note says `Rc> cannot be sent between threads safely`. The reason -for this is in the error message, which, once distilled, says `the trait bound -Send is not satisfied`. We’re going to talk about `Send` in the next section; -it’s one of the traits that ensures the types we use with threads are meant for -use in concurrent situations. - - - +Wow, that error message is very wordy! Here are some important parts to focus +on: the first inline error says `` `std::rc::Rc>` cannot +be sent between threads safely ``. The reason for this is in the next important +part to focus on, the error message. The distilled error message says `` the +trait bound `Send` is not satisfied ``. We’ll talk about `Send` in the next +section: it’s one of the traits that ensures the types we use with threads are +meant for use in concurrent situations. Unfortunately, `Rc` is not safe to share across threads. When `Rc` manages the reference count, it adds to the count for each call to `clone` and -subtracts from the count when each clone is dropped, but it doesn’t use any +subtracts from the count when each clone is dropped. But it doesn’t use any concurrency primitives to make sure that changes to the count can’t be -interrupted by another thread. This could lead to wrong counts: subtle bugs -that could in turn lead to memory leaks or a value being dropped before we’re -done with it. What we need is a type exactly like `Rc`, but that makes -changes to the reference count in a thread-safe way. +interrupted by another thread. This could lead to wrong counts—subtle bugs that +could in turn lead to memory leaks or a value being dropped before we’re done +with it. What we need is a type exactly like `Rc` but one that makes changes +to the reference count in a thread-safe way. #### Atomic Reference Counting with `Arc` -Luckily for us, there *is* a type like `Rc` that’s safe to use in concurrent -situations: `Arc`. The ‘a’ stands for *atomic*, meaning it’s an *atomically +Fortunately, `Arc` *is* a type like `Rc` that is safe to use in +concurrent situations. The ‘a’ stands for *atomic*, meaning it’s an *atomically reference counted* type. Atomics are an additional kind of concurrency -primitive that we won’t cover in detail here; see the standard library -documentation for `std::sync::atomic` for more details. What you need to know -here is that atomics work like primitive types, but are safe to share across -threads. +primitive that we won’t cover in detail here: see the standard library +documentation for `std::sync::atomic` for more details. At this point, you just +need to know that atomics work like primitive types but are safe to share +across threads. -You might then wonder why all primitive types aren’t atomic, and why standard +You might then wonder why all primitive types aren’t atomic and why standard library types aren’t implemented to use `Arc` by default. The reason is that thread safety comes with a performance penalty that you only want to pay when -you really need to. If you’re only doing operations on values within a single -thread, your code can run faster if it doesn’t have to enforce the guarantees -atomics provide. +you really need to. If you’re just performing operations on values within a +single thread, your code can run faster if it doesn’t have to enforce the +guarantees atomics provide. -Back to our example: `Arc` and `Rc` have the same API, so we fix our -program by changing the `use` line and the call to `new`. The code in Listing -16-15 will finally compile and run: +Let’s return to our example: `Arc` and `Rc` have the same API, so we fix +our program by changing the `use` line and the call to `new`. The code in +Listing 16-15 will finally compile and run: Filename: src/main.rs @@ -385,7 +357,7 @@ fn main() { let mut handles = vec![]; for _ in 0..10 { - let counter = Arc::clone(&counter); + let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); @@ -405,49 +377,38 @@ fn main() { Listing 16-15: Using an `Arc` to wrap the `Mutex` to be able to share ownership across multiple threads -This will print: +This code will print the following: ```text Result: 10 ``` We did it! We counted from 0 to 10, which may not seem very impressive, but it -did teach us a lot about `Mutex` and thread safety! This structure could -also be used to do more complicated operations than just incrementing a -counter: these methods allow us to divide calculations up into independent -parts, which we could split across threads, and then we can use a `Mutex` to -have each thread update the final result with its part. +did teach us a lot about `Mutex` and thread safety. You could also use this +program’s structure to do more complicated operations than just incrementing a +counter. Using this strategy, you can divide a calculation into independent +parts, split those parts across threads, then use a `Mutex` to have each +thread update the final result with its part. -### Similarities between `RefCell`/`Rc` and `Mutex`/`Arc` +### Similarities Between `RefCell`/`Rc` and `Mutex`/`Arc` -You may have noticed that `counter` is immutable but we could get a mutable +You might have noticed that `counter` is immutable, but we could get a mutable reference to the value inside it; this means `Mutex` provides interior mutability, like the `Cell` family does. In the same way we used `RefCell` in Chapter 15 to allow us to mutate contents inside an `Rc`, we use -`Mutex` to mutate contents inside of an `Arc`. +`Mutex` to mutate contents inside an `Arc`. -Another thing to note is that Rust can’t prevent us from all kinds of logic -errors when using `Mutex`. Recall from Chapter 15 that using `Rc` came +Another detail to note is that Rust can’t protect us from all kinds of logic +errors when we use `Mutex`. Recall in Chapter 15 that using `Rc` came with the risk of creating reference cycles, where two `Rc` values refer to -each other, causing memory leaks. Similarly, `Mutex` comes the risk of -*deadlocks*. These occur when an operation needs to lock two resources and two -threads have each acquired one of the locks, causing them to wait for each -other forever. If you’re interested in this topic, try creating a Rust program -that has a deadlock, then research deadlock mitigation strategies for mutexes -in any language, and have a go at implementing them in Rust. The standard -library API documentation for `Mutex` and `MutexGuard` will have useful -information. +each other, causing memory leaks. Similarly, `Mutex` comes with the risk of +creating *deadlocks*. These occur when an operation needs to lock two resources +and two threads have each acquired one of the locks, causing them to wait for +each other forever. If you’re interested in deadlocks, try creating a Rust +program that has a deadlock; then research deadlock mitigation strategies for +mutexes in any language and have a go at implementing them in Rust. The +standard library API documentation for `Mutex` and `MutexGuard` offers +useful information. - - - - -Let’s round out this chapter by talking about the `Send` and `Sync` traits and -how we could use them with custom types. +We’ll round out this chapter by talking about the `Send` and `Sync` traits, and +how we can use them with custom types. diff --git a/src/doc/book/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md b/src/doc/book/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md index 4603a668b4..cddad071f7 100644 --- a/src/doc/book/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md +++ b/src/doc/book/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md @@ -1,29 +1,29 @@ ## Extensible Concurrency with the `Sync` and `Send` Traits -Interestingly, the Rust language itself knows *very* little about concurrency. -Almost everything we’ve talked about so far in this chapter has been part of -the standard library, not the language. Our concurrency options are not limited -to the language or the standard library, meaning we can write our own -concurrency options or use ones others have written. +Interestingly, the Rust language has *very* few concurrency features. Almost +every concurrency feature we’ve talked about so far in this chapter has been +part of the standard library, not the language. Our options for handling +concurrency are not limited to the language or the standard library; we can +write our own concurrency features or use those written by others. -There *are* two concurrency concepts embedded in the language, however: the +However, two concurrency concepts are embedded in the language: the `std::marker` traits `Sync` and `Send`. ### Allowing Transference of Ownership Between Threads with `Send` The `Send` marker trait indicates that ownership of the type implementing -`Send` may be transferred between threads. Almost every Rust type is `Send`, +`Send` can be transferred between threads. Almost every Rust type is `Send`, but there are some exceptions, including `Rc`: this cannot be `Send` because if we cloned an `Rc` value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time. For this reason, `Rc` is implemented for use in single-threaded situations -where you don’t want to pay the threadsafe performance penalty. +where you don’t want to pay the thread-safe performance penalty. -In this way Rust’s type system and trait bounds ensure we can never +Therefore, Rust’s type system and trait bounds ensure that we can never accidentally send an `Rc` value across threads unsafely. When we tried to do -this in Listing 16-14, we got an error that said `the trait Send is not -implemented for Rc>`. When we switched to `Arc`, which is `Send`, -the code compiled. +this in Listing 16-14, we got the error `the trait Send is not implemented for +Rc>`. When we switched to `Arc`, which is `Send`, the code +compiled. Any type composed entirely of `Send` types is automatically marked as `Send` as well. Almost all primitive types are `Send`, aside from raw pointers, which @@ -32,54 +32,57 @@ we’ll discuss in Chapter 19. ### Allowing Access from Multiple Threads with `Sync` The `Sync` marker trait indicates that it is safe for the type implementing -`Sync` to be referenced from multiple threads. Another way to say this is that -any type `T` is `Sync` if `&T` (a reference to `T`) is `Send`, meaning the -reference can be sent safely to another thread. In a similar manner as `Send`, -primitive types are `Sync` and types composed entirely of types that are `Sync` -are also `Sync`. +`Sync` to be referenced from multiple threads. In other words, any type `T` is +`Sync` if `&T` (a reference to `T`) is `Send`, meaning the reference can be +sent safely to another thread. Similar to `Send`, primitive types are `Sync` +and types composed entirely of types that are `Sync` are also `Sync`. -`Rc` is also not `Sync`, for the same reasons that it’s not `Send`. -`RefCell` (which we talked about in Chapter 15) and the family of related -`Cell` types are not `Sync`. The implementation of borrow checking that -`RefCell` does at runtime is not threadsafe. `Mutex` is `Sync`, and can -be used to share access with multiple threads as we saw in the previous section. +The smart pointer `Rc` is also not `Sync` for the same reasons that it’s not +`Send`. The `RefCell` type (which we talked about in Chapter 15) and the +family of related `Cell` types are not `Sync`. The implementation of borrow +checking that `RefCell` does at runtime is not thread-safe. The smart +pointer `Mutex` is `Sync` and can be used to share access with multiple +threads, as you saw in the “Sharing a `Mutex` Between Multiple Threads†+section. -### Implementing `Send` and `Sync` Manually is Unsafe +### Implementing `Send` and `Sync` Manually Is Unsafe Because types that are made up of `Send` and `Sync` traits are automatically -also `Send` and `Sync`, we don’t have to implement those traits ourselves. As +also `Send` and `Sync`, we don’t have to implement those traits manually. As marker traits, they don’t even have any methods to implement. They’re just -useful for enforcing concurrency-related invariants. +useful for enforcing invariants related to concurrency. Manually implementing these traits involves implementing unsafe Rust code. -We’re going to be talking about using unsafe Rust code in Chapter 19; for now, -the important information is that building new concurrent types not made up of -`Send` and `Sync` parts requires careful thought, in order to uphold the safety -guarantees. [The Nomicon] has more information about these guarantees and how -to uphold them. +We’ll talk about using unsafe Rust code in Chapter 19; for now, the important +information is that building new concurrent types not made up of `Send` and +`Sync` parts requires careful thought to uphold the safety guarantees. [The +Rustonomicon] has more information about these guarantees and how to uphold +them. -[The Nomicon]: https://doc.rust-lang.org/stable/nomicon/ +[The Rustonomicon]: https://doc.rust-lang.org/stable/nomicon/ ## Summary -This isn’t the last we’ll see of concurrency in this book; the project in -Chapter 20 will use these concepts in a more realistic situation than the -smaller examples discussed here. +This isn’t the last you’ll see of concurrency in this book: the project in +Chapter 20 will use the concepts examined in this chapter in a more realistic +situation than the smaller examples discussed here. -As we mentioned, since very little of how Rust deals with concurrency is part -of the language, many concurrency solutions are implemented as crates. These -evolve more quickly than the standard library; search online for the current -state-of-the-art crates to use in multithreaded situations. +As mentioned earlier, because very little of how Rust handles concurrency is +part of the language, many concurrency solutions are implemented as crates. +These evolve more quickly than the standard library, so be sure to search +online for the current, state-of-the-art crates to use in multithreaded +situations. -Rust provides channels for message passing and smart pointer types like -`Mutex` and `Arc` that are safe to use in concurrent contexts. The type -system and the borrow checker will make sure the code using these solutions -won’t end up with data races or invalid references. Once we get our code -compiling, we can rest assured that it will happily run on multiple threads -without the kinds of hard-to-track-down bugs common in other languages. -Concurrent programming is no longer something to be afraid of: go forth and -make your programs concurrent, fearlessly! +The Rust standard library provides channels for message passing and smart +pointer types, such as `Mutex` and `Arc`, that are safe to use in +concurrent contexts. The type system and the borrow checker ensure that the +code using these solutions won’t end up with data races or invalid references. +Once we get our code to compile, we can rest assured that it will happily run +on multiple threads without the kinds of hard-to-track-down bugs common in +other languages. Concurrent programming is no longer a concept to be afraid of: +go forth and make your programs concurrent, fearlessly! + +Next, we’ll talk about idiomatic ways to model problems and structure solutions +as your Rust programs get bigger. In addition, we’ll discuss how Rust’s idioms +relate to those you might be familiar with from object oriented programming. -Next, let’s talk about idiomatic ways to model problems and structure solutions -as your Rust programs get bigger, and how Rust’s idioms relate to those you -might be familiar with from Object Oriented Programming. 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 b84c5547c6..e382d87bbf 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 @@ -167,7 +167,7 @@ type `Button` or all of type `TextField`. If you’ll only ever have homogeneous collections, using generics and trait bounds is preferable since the definitions will be monomorphized at compile time to use the concrete types. -With the the method using trait objects, on the other hand, one `Screen` +With the method using trait objects, on the other hand, one `Screen` instance can hold a `Vec` that contains a `Box + + + +